From 62198b03cde2790b5e69d44b79d1d072f8a2456c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= Date: Fri, 20 Sep 2024 00:50:35 +0200 Subject: [PATCH 01/93] fix: `avm/ptn/deployment/import-image-to-acr` fixes bugs handling newImageName (#3329) ## Description Fixes bugs handling newImageName Closes #3326 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.deployment-script.import-image-to-acr](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml/badge.svg?branch=import-image-fixes)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [x] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/deployment-script/import-image-to-acr/README.md | 6 +++--- avm/ptn/deployment-script/import-image-to-acr/main.bicep | 6 ++++-- avm/ptn/deployment-script/import-image-to-acr/main.json | 6 +++--- .../import-image-to-acr/tests/e2e/max/main.test.bicep | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/avm/ptn/deployment-script/import-image-to-acr/README.md b/avm/ptn/deployment-script/import-image-to-acr/README.md index 42038de2c6..9015f8760e 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/README.md +++ b/avm/ptn/deployment-script/import-image-to-acr/README.md @@ -115,7 +115,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr cleanupPreference: 'OnExpiration' location: '' managedIdentities: '' - newImageName: 'your-image-name:tag' + newImageName: 'application/your-image-name:tag' overwriteExistingImage: true storageAccountResourceId: '' subnetResourceIds: '' @@ -163,7 +163,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr "value": "" }, "newImageName": { - "value": "your-image-name:tag" + "value": "application/your-image-name:tag" }, "overwriteExistingImage": { "value": true @@ -395,7 +395,7 @@ The new image name in the ACR. You can use this to import a publically available - Required: No - Type: string -- Default: `[last(split(parameters('image'), '/'))]` +- Default: `[string(skip(parameters('image'), add(indexOf(parameters('image'), '/'), 1)))]` - Example: `your-image-name:tag` ### Parameter: `overwriteExistingImage` diff --git a/avm/ptn/deployment-script/import-image-to-acr/main.bicep b/avm/ptn/deployment-script/import-image-to-acr/main.bicep index 64be560c36..61534011ce 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/main.bicep +++ b/avm/ptn/deployment-script/import-image-to-acr/main.bicep @@ -47,7 +47,7 @@ param sourceRegistryPassword string = '' @metadata({ example: 'your-image-name:tag' }) -param newImageName string = last(split(image, '/')) +param newImageName string = string(skip(image, indexOf(image, '/') + 1)) @description('Optional. The image will be overwritten if it already exists in the ACR with the same tag. Default is false.') param overwriteExistingImage bool = false @@ -234,7 +234,9 @@ output deploymentScriptOutput string[] = imageImport.outputs.deploymentScriptLog @description('An array of the imported images.') output importedImage importedImageType = { originalImage: image - acrHostedImage: '${acr.properties.loginServer}${string(skip(image, indexOf(image,'/')))}' + acrHostedImage: empty(newImageName) + ? '${acr.properties.loginServer}${string(skip(image, indexOf(image,'/')))}' + : '${acr.properties.loginServer}/${newImageName}' } // ================ // diff --git a/avm/ptn/deployment-script/import-image-to-acr/main.json b/avm/ptn/deployment-script/import-image-to-acr/main.json index 51751e27f8..4f8a4504ae 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/main.json +++ b/avm/ptn/deployment-script/import-image-to-acr/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "15179702678978782456" + "templateHash": "13166673091432959100" }, "name": "import-image-to-acr", "description": "This modules deployes an image to an Azure Container Registry.", @@ -127,7 +127,7 @@ }, "newImageName": { "type": "string", - "defaultValue": "[last(split(parameters('image'), '/'))]", + "defaultValue": "[string(skip(parameters('image'), add(indexOf(parameters('image'), '/'), 1)))]", "metadata": { "example": "your-image-name:tag", "description": "Optional. The new image name in the ACR. You can use this to import a publically available image with a custom name for later updating from e.g., your build pipeline." @@ -910,7 +910,7 @@ }, "value": { "originalImage": "[parameters('image')]", - "acrHostedImage": "[format('{0}{1}', reference('acr').loginServer, string(skip(parameters('image'), indexOf(parameters('image'), '/'))))]" + "acrHostedImage": "[if(empty(parameters('newImageName')), format('{0}{1}', reference('acr').loginServer, string(skip(parameters('image'), indexOf(parameters('image'), '/')))), format('{0}/{1}', reference('acr').loginServer, parameters('newImageName')))]" } } } diff --git a/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep b/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep index 3c7e75c684..8cd3fd3db1 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep +++ b/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep @@ -69,7 +69,7 @@ module testDeployment '../../../main.bicep' = [ // commented out, as the user is not available in the test environment // sourceRegistryUsername: 'username' // sourceRegistryPassword: keyVault.getSecret(dependencies.outputs.keyVaultSecretName) - newImageName: 'your-image-name:tag' + newImageName: 'application/your-image-name:tag' cleanupPreference: 'OnExpiration' assignRbacRole: true managedIdentities: { userAssignedResourcesIds: [dependencies.outputs.managedIdentityResourceId] } From c447185e556f0586ae0e78c254886d9144978bd2 Mon Sep 17 00:00:00 2001 From: Fabio Masciotra Date: Fri, 20 Sep 2024 01:18:35 +0200 Subject: [PATCH 02/93] feat: experimental use of 'discriminator' for vpng-gw module (#2667) ## Description Closes https://github.com/Azure/bicep-registry-modules/issues/1869 Reviewed the code with the use of 'discriminator' for the UDT. Added the following test-cases: 1. BGP: VPN Active Passive with BGP config but no APIPA 2. BGPAA: VPN Active Active with BGP config but no APIPA 3. BGPAPIPA: VPN Active Passive with BGP config and APIPA 4. BGPAAAPIPA: VPN Active Active with BGP config and APIPA Plus other test-cases without BGP ## Pipeline Reference [![avm.res.network.virtual-network-gateway](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml/badge.svg?branch=vnetgw-draft)](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml) ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../network/virtual-network-gateway/README.md | 833 ++++++++++++++++-- .../virtual-network-gateway/main.bicep | 135 ++- .../network/virtual-network-gateway/main.json | 200 ++++- .../tests/e2e/aadvpn/main.test.bicep | 6 +- .../e2e/activeActiveBGP/dependencies.bicep | 49 ++ .../tests/e2e/activeActiveBGP/main.test.bicep | 83 ++ .../activeActiveBgpAPIPA/dependencies.bicep | 49 ++ .../e2e/activeActiveBgpAPIPA/main.test.bicep | 85 ++ .../e2e/activeActiveNoBGP/dependencies.bicep | 49 ++ .../e2e/activeActiveNoBGP/main.test.bicep | 83 ++ .../e2e/activePassiveBGP/dependencies.bicep | 49 ++ .../e2e/activePassiveBGP/main.test.bicep | 85 ++ .../e2e/activePassiveNoBGP/dependencies.bicep | 49 ++ .../e2e/activePassiveNoBGP/main.test.bicep | 83 ++ .../tests/e2e/defaults/main.test.bicep | 3 + .../tests/e2e/expressRoute/main.test.bicep | 3 + .../tests/e2e/max/main.test.bicep | 7 +- .../tests/e2e/vpn-no-az/main.test.bicep | 3 + .../tests/e2e/vpn/main.test.bicep | 4 +- .../tests/e2e/waf-aligned/main.test.bicep | 7 +- .../virtual-network-gateway/version.json | 2 +- 21 files changed, 1699 insertions(+), 168 deletions(-) create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep diff --git a/avm/res/network/virtual-network-gateway/README.md b/avm/res/network/virtual-network-gateway/README.md index 83cde965b0..644177396e 100644 --- a/avm/res/network/virtual-network-gateway/README.md +++ b/avm/res/network/virtual-network-gateway/README.md @@ -31,12 +31,17 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-network-gateway:`. - [AAD-VPN](#example-1-aad-vpn) -- [Using only defaults](#example-2-using-only-defaults) -- [ExpressRoute](#example-3-expressroute) -- [Using large parameter set](#example-4-using-large-parameter-set) -- [Using SKU without Availability Zones](#example-5-using-sku-without-availability-zones) -- [VPN](#example-6-vpn) -- [WAF-aligned](#example-7-waf-aligned) +- [VPN Active Active with BGP settings](#example-2-vpn-active-active-with-bgp-settings) +- [VPN Active Active with BGP settings](#example-3-vpn-active-active-with-bgp-settings) +- [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 without BGP settings](#example-6-vpn-active-passive-without-bgp-settings) +- [Using only defaults](#example-7-using-only-defaults) +- [ExpressRoute](#example-8-expressroute) +- [Using large parameter set](#example-9-using-large-parameter-set) +- [Using SKU without Availability Zones](#example-10-using-sku-without-availability-zones) +- [VPN](#example-11-vpn) +- [WAF-aligned](#example-12-waf-aligned) ### Example 1: _AAD-VPN_ @@ -52,32 +57,635 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgavpn001' + skuName: 'VpnGw2AZ' + vNetResourceId: '' + // Non-required parameters + domainNameLabel: [ + 'dm-nvgavpn' + ] + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + vpnClientAadConfiguration: { + aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' + aadIssuer: '' + aadTenant: '' + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnClientProtocols: [ + 'OpenVPN' + ] + } + vpnType: 'RouteBased' + } +} +``` + + +

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgavpn001" + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "domainNameLabel": { + "value": [ + "dm-nvgavpn" + ] + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "vpnClientAadConfiguration": { + "value": { + "aadAudience": "41b23e61-6c1e-4545-b367-cd054e0ed4b4", + "aadIssuer": "", + "aadTenant": "", + "vpnAuthenticationTypes": [ + "AAD" + ], + "vpnClientProtocols": [ + "OpenVPN" + ] + } + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +### Example 2: _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' + skuName: 'VpnGw2AZ' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaab' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgaab001" + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "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 + ] + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +### Example 3: _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' + skuName: 'VpnGw2AZ' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaaa' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "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" + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "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 + ] + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "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' + skuName: 'VpnGw2AZ' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaa' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgaa001" + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "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 + ] + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "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: 'nvngavpn001' + name: 'nvgapb001' skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters - activeActive: false + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true domainNameLabel: [ - 'dm-nvngavpn' + 'dm-nvgapb' ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' location: '' publicIpZones: [ 1 2 3 ] - vpnClientAadConfiguration: { - aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' - aadIssuer: '' - aadTenant: '' - vpnAuthenticationTypes: [ - 'AAD' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "asn": 65815, + "clusterMode": "activePassiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ] + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgapb001" + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgapb" ] - vpnClientProtocols: [ - 'OpenVPN' + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 ] + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +### Example 6: _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' + skuName: 'VpnGw2AZ' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgap' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } } @@ -96,11 +704,16 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, "gatewayType": { "value": "Vpn" }, "name": { - "value": "nvngavpn001" + "value": "nvgap001" }, "skuName": { "value": "VpnGw2AZ" @@ -109,14 +722,26 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "value": "" }, // Non-required parameters - "activeActive": { - "value": false + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true }, "domainNameLabel": { "value": [ - "dm-nvngavpn" + "dm-nvgap" ] }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, "location": { "value": "" }, @@ -127,18 +752,8 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, - "vpnClientAadConfiguration": { - "value": { - "aadAudience": "41b23e61-6c1e-4545-b367-cd054e0ed4b4", - "aadIssuer": "", - "aadTenant": "", - "vpnAuthenticationTypes": [ - "AAD" - ], - "vpnClientProtocols": [ - "OpenVPN" - ] - } + "vpnGatewayGeneration": { + "value": "Generation2" }, "vpnType": { "value": "RouteBased" @@ -150,7 +765,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-### Example 2: _Using only defaults_ +### Example 7: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -164,6 +779,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } gatewayType: 'Vpn' name: 'nvgmin001' skuName: 'VpnGw2AZ' @@ -192,6 +810,11 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, "gatewayType": { "value": "Vpn" }, @@ -222,7 +845,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-### Example 3: _ExpressRoute_ +### Example 8: _ExpressRoute_ This instance deploys the module with the ExpressRoute set of required parameters. @@ -236,6 +859,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activePassiveBgp' + } gatewayType: 'ExpressRoute' name: 'nvger001' skuName: 'ErGw1AZ' @@ -268,6 +894,11 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveBgp" + } + }, "gatewayType": { "value": "ExpressRoute" }, @@ -306,7 +937,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-### Example 4: _Using large parameter set_ +### Example 9: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -320,12 +951,23 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + activeGatewayPipName: 'nvgmax001-pip2' + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + } gatewayType: 'Vpn' name: 'nvgmax001' skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters - activeActive: true allowRemoteVnetTraffic: true diagnosticSettings: [ { @@ -435,6 +1077,20 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "activeGatewayPipName": "nvgmax001-pip2", + "clusterMode": "activeActiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ], + "secondCustomBgpIpAddresses": [ + "169.254.22.4", + "169.254.22.5" + ] + } + }, "gatewayType": { "value": "Vpn" }, @@ -448,9 +1104,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "value": "" }, // Non-required parameters - "activeActive": { - "value": true - }, "allowRemoteVnetTraffic": { "value": true }, @@ -580,7 +1233,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-### Example 5: _Using SKU without Availability Zones_ +### Example 10: _Using SKU without Availability Zones_ This instance deploys the module with a SKU that does not support Availability Zones. @@ -594,6 +1247,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } gatewayType: 'Vpn' name: 'nvgnaz001' skuName: 'VpnGw1' @@ -617,6 +1273,11 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, "gatewayType": { "value": "Vpn" }, @@ -640,7 +1301,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-### Example 6: _VPN_ +### Example 11: _VPN_ This instance deploys the module with the VPN set of required parameters. @@ -654,12 +1315,14 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } gatewayType: 'Vpn' name: 'nvgvpn001' skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters - activeActive: true allowRemoteVnetTraffic: true disableIPSecReplayProtection: true domainNameLabel: [ @@ -693,6 +1356,11 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, "gatewayType": { "value": "Vpn" }, @@ -706,9 +1374,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "value": "" }, // Non-required parameters - "activeActive": { - "value": true - }, "allowRemoteVnetTraffic": { "value": true }, @@ -752,7 +1417,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-### Example 7: _WAF-aligned_ +### Example 12: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -766,12 +1431,23 @@ 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' skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters - activeActive: true allowRemoteVnetTraffic: true diagnosticSettings: [ { @@ -862,6 +1538,20 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "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" }, @@ -875,9 +1565,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "value": "" }, // Non-required parameters - "activeActive": { - "value": true - }, "allowRemoteVnetTraffic": { "value": true }, @@ -992,6 +1679,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: | 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. | @@ -1001,17 +1689,13 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: | Parameter | Type | Description | | :-- | :-- | :-- | -| [`activeActive`](#parameter-activeactive) | bool | Value to specify if the Gateway should be deployed in active-active or active-passive configuration. | -| [`activeGatewayPipName`](#parameter-activegatewaypipname) | string | Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip' suffix will be appended to the gateway's name. | | [`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. | -| [`asn`](#parameter-asn) | int | ASN value. | | [`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 configuration, 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. | -| [`enableBgp`](#parameter-enablebgp) | bool | Value to specify if BGP is enabled or not. | | [`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. | @@ -1031,6 +1715,13 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: | [`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. @@ -1088,22 +1779,6 @@ Virtual Network resource ID. - Required: Yes - Type: string -### Parameter: `activeActive` - -Value to specify if the Gateway should be deployed in active-active or active-passive configuration. - -- Required: No -- Type: bool -- Default: `True` - -### Parameter: `activeGatewayPipName` - -Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip' suffix will be appended to the gateway's name. - -- Required: No -- Type: string -- Default: `[format('{0}-pip2', parameters('name'))]` - ### Parameter: `allowRemoteVnetTraffic` Configure this gateway to accept traffic from other Azure Virtual Networks. This configuration does not support connectivity to Azure Virtual WAN. @@ -1120,14 +1795,6 @@ Configures this gateway to accept traffic from remote Virtual WAN networks. - Type: bool - Default: `False` -### Parameter: `asn` - -ASN value. - -- Required: No -- Type: int -- Default: `65815` - ### Parameter: `clientRevokedCertThumbprint` Thumbprint of the revoked certificate. This would revoke VPN client certificates matching this thumbprint from connecting to the VNet. @@ -1306,14 +1973,6 @@ DNS name(s) of the Public IP resource(s). If you enabled active-active configura - Type: array - Default: `[]` -### Parameter: `enableBgp` - -Value to specify if BGP is enabled or not. - -- Required: No -- Type: bool -- Default: `True` - ### Parameter: `enableBgpRouteTranslationForNat` EnableBgpRouteTranslationForNat flag. Can only be used when "natRules" are enabled on the Virtual Network Gateway. diff --git a/avm/res/network/virtual-network-gateway/main.bicep b/avm/res/network/virtual-network-gateway/main.bicep index 6b73abca5d..15b0247f69 100644 --- a/avm/res/network/virtual-network-gateway/main.bicep +++ b/avm/res/network/virtual-network-gateway/main.bicep @@ -11,9 +11,6 @@ param location string = resourceGroup().location @description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway. If it\'s not provided, a \'-pip\' suffix will be appended to the gateway\'s name.') param gatewayPipName string = '${name}-pip1' -@description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip\' suffix will be appended to the gateway\'s name.') -param activeGatewayPipName string = '${name}-pip2' - @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 = '' @@ -70,14 +67,8 @@ param vpnType string = 'RouteBased' @description('Required. Virtual Network resource ID.') param vNetResourceId string -@description('Optional. Value to specify if the Gateway should be deployed in active-active or active-passive configuration.') -param activeActive bool = true - -@description('Optional. Value to specify if BGP is enabled or not.') -param enableBgp bool = true - -@description('Optional. ASN value.') -param asn int = 65815 +@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 = '' @@ -140,25 +131,53 @@ param vpnClientAadConfiguration object = {} // Other Variables var gatewayPipAllocationMethod = skuName == 'Basic' ? 'Dynamic' : 'Static' -var isActiveActiveValid = gatewayType != 'ExpressRoute' ? activeActive : false -var virtualGatewayPipNameVar = isActiveActiveValid +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 activeGatewayPipNameVar = isActiveActive ? (clusterSettings.?activeGatewayPipName ?? '${name}-pip2') : null + +var virtualGatewayPipNameVar = isActiveActive ? [ gatewayPipName - activeGatewayPipName + activeGatewayPipNameVar ] : [ gatewayPipName ] -var vpnTypeVar = gatewayType != 'ExpressRoute' ? vpnType : 'PolicyBased' +// 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' + } + ] + } -var isBgpValid = gatewayType != 'ExpressRoute' ? enableBgp : false -var bgpSettings = { - asn: asn -} -// Potential configurations (active-active vs active-passive) -var ipConfiguration = isActiveActiveValid +// Potential IP configurations (active-active vs active-passive) +var ipConfiguration = isActiveActive ? [ { properties: { @@ -179,8 +198,8 @@ var ipConfiguration = isActiveActiveValid id: '${vNetResourceId}/subnets/GatewaySubnet' } publicIPAddress: { - id: isActiveActiveValid - ? az.resourceId('Microsoft.Network/publicIPAddresses', activeGatewayPipName) + id: isActiveActive + ? az.resourceId('Microsoft.Network/publicIPAddresses', activeGatewayPipNameVar) : az.resourceId('Microsoft.Network/publicIPAddresses', gatewayPipName) } } @@ -331,13 +350,13 @@ resource virtualNetworkGateway 'Microsoft.Network/virtualNetworkGateways@2023-04 tags: tags properties: { ipConfigurations: ipConfiguration - activeActive: isActiveActiveValid + activeActive: isActiveActive allowRemoteVnetTraffic: allowRemoteVnetTraffic allowVirtualWanTraffic: allowVirtualWanTraffic - enableBgp: isBgpValid - bgpSettings: isBgpValid ? bgpSettings : null + enableBgp: isBgp + bgpSettings: isBgp ? bgpSettingsVar : null disableIPSecReplayProtection: disableIPSecReplayProtection - enableDnsForwarding: gatewayType == 'ExpressRoute' ? enableDnsForwarding : null + enableDnsForwarding: !isExpressRoute ? enableDnsForwarding : null enablePrivateIpAddress: enablePrivateIpAddress enableBgpRouteTranslationForNat: enableBgpRouteTranslationForNat gatewayType: gatewayType @@ -365,11 +384,11 @@ module virtualNetworkGateway_natRules 'nat-rule/main.bicep' = [ params: { name: natRule.name virtualNetworkGatewayName: virtualNetworkGateway.name - externalMappings: contains(natRule, 'externalMappings') ? natRule.externalMappings : [] - internalMappings: contains(natRule, 'internalMappings') ? natRule.internalMappings : [] - ipConfigurationId: contains(natRule, 'ipConfigurationId') ? natRule.ipConfigurationId : '' - mode: contains(natRule, 'mode') ? natRule.mode : '' - type: contains(natRule, 'type') ? natRule.type : '' + externalMappings: natRule.?externalMappings ?? [] + internalMappings: natRule.?internalMappings ?? [] + ipConfigurationId: natRule.?ipConfigurationId ?? '' + mode: natRule.?mode ?? '' + type: natRule.?type ?? '' } } ] @@ -533,3 +552,55 @@ type diagnosticSettingType = { @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. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') + activeGatewayPipName: 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. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') + activeGatewayPipName: 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/res/network/virtual-network-gateway/main.json b/avm/res/network/virtual-network-gateway/main.json index 19876a6210..5e1b4bdf4c 100644 --- a/avm/res/network/virtual-network-gateway/main.json +++ b/avm/res/network/virtual-network-gateway/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "15596993518588024968" + "templateHash": "973776533492793692" }, "name": "Virtual Network Gateways", "description": "This module deploys a Virtual Network Gateway.", @@ -230,6 +230,132 @@ } }, "nullable": true + }, + "activePassiveNoBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activePassiveNoBgp" + ] + } + } + }, + "activeActiveNoBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activeActiveNoBgp" + ] + }, + "activeGatewayPipName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip2' suffix will be appended to the gateway's name." + } + } + } + }, + "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" + ] + }, + "activeGatewayPipName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip2' suffix will be appended to the gateway's name." + } + }, + "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": { @@ -253,13 +379,6 @@ "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway. If it's not provided, a '-pip' suffix will be appended to the gateway's name." } }, - "activeGatewayPipName": { - "type": "string", - "defaultValue": "[format('{0}-pip2', parameters('name'))]", - "metadata": { - "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip' suffix will be appended to the gateway's name." - } - }, "publicIPPrefixResourceId": { "type": "string", "defaultValue": "", @@ -345,25 +464,10 @@ "description": "Required. Virtual Network resource ID." } }, - "activeActive": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Value to specify if the Gateway should be deployed in active-active or active-passive configuration." - } - }, - "enableBgp": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Value to specify if BGP is enabled or not." - } - }, - "asn": { - "type": "int", - "defaultValue": 65815, + "clusterSettings": { + "$ref": "#/definitions/clusterSettingType", "metadata": { - "description": "Optional. ASN value." + "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": { @@ -498,14 +602,14 @@ } ], "gatewayPipAllocationMethod": "[if(equals(parameters('skuName'), 'Basic'), 'Dynamic', 'Static')]", - "isActiveActiveValid": "[if(not(equals(parameters('gatewayType'), 'ExpressRoute')), parameters('activeActive'), false())]", - "virtualGatewayPipNameVar": "[if(variables('isActiveActiveValid'), createArray(parameters('gatewayPipName'), parameters('activeGatewayPipName')), createArray(parameters('gatewayPipName')))]", - "vpnTypeVar": "[if(not(equals(parameters('gatewayType'), 'ExpressRoute')), parameters('vpnType'), 'PolicyBased')]", - "isBgpValid": "[if(not(equals(parameters('gatewayType'), 'ExpressRoute')), parameters('enableBgp'), false())]", - "bgpSettings": { - "asn": "[parameters('asn')]" - }, - "ipConfiguration": "[if(variables('isActiveActiveValid'), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1'), createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(variables('isActiveActiveValid'), resourceId('Microsoft.Network/publicIPAddresses', parameters('activeGatewayPipName')), resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName'))))), 'name', 'vNetGatewayConfig2')), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1')))]", + "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')))]", + "activeGatewayPipNameVar": "[if(variables('isActiveActive'), coalesce(tryGet(parameters('clusterSettings'), 'activeGatewayPipName'), format('{0}-pip2', parameters('name'))), null())]", + "virtualGatewayPipNameVar": "[if(variables('isActiveActive'), createArray(parameters('gatewayPipName'), variables('activeGatewayPipNameVar')), createArray(parameters('gatewayPipName')))]", + "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', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1'), createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(variables('isActiveActive'), resourceId('Microsoft.Network/publicIPAddresses', variables('activeGatewayPipNameVar')), resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName'))))), 'name', 'vNetGatewayConfig2')), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), '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')]", @@ -545,13 +649,13 @@ "tags": "[parameters('tags')]", "properties": { "ipConfigurations": "[variables('ipConfiguration')]", - "activeActive": "[variables('isActiveActiveValid')]", + "activeActive": "[variables('isActiveActive')]", "allowRemoteVnetTraffic": "[parameters('allowRemoteVnetTraffic')]", "allowVirtualWanTraffic": "[parameters('allowVirtualWanTraffic')]", - "enableBgp": "[variables('isBgpValid')]", - "bgpSettings": "[if(variables('isBgpValid'), variables('bgpSettings'), null())]", + "enableBgp": "[variables('isBgp')]", + "bgpSettings": "[if(variables('isBgp'), variables('bgpSettingsVar'), null())]", "disableIPSecReplayProtection": "[parameters('disableIPSecReplayProtection')]", - "enableDnsForwarding": "[if(equals(parameters('gatewayType'), 'ExpressRoute'), parameters('enableDnsForwarding'), null())]", + "enableDnsForwarding": "[if(not(variables('isExpressRoute')), parameters('enableDnsForwarding'), null())]", "enablePrivateIpAddress": "[parameters('enablePrivateIpAddress')]", "enableBgpRouteTranslationForNat": "[parameters('enableBgpRouteTranslationForNat')]", "gatewayType": "[parameters('gatewayType')]", @@ -1329,11 +1433,21 @@ "virtualNetworkGatewayName": { "value": "[parameters('name')]" }, - "externalMappings": "[if(contains(parameters('natRules')[copyIndex()], 'externalMappings'), createObject('value', parameters('natRules')[copyIndex()].externalMappings), createObject('value', createArray()))]", - "internalMappings": "[if(contains(parameters('natRules')[copyIndex()], 'internalMappings'), createObject('value', parameters('natRules')[copyIndex()].internalMappings), createObject('value', createArray()))]", - "ipConfigurationId": "[if(contains(parameters('natRules')[copyIndex()], 'ipConfigurationId'), createObject('value', parameters('natRules')[copyIndex()].ipConfigurationId), createObject('value', ''))]", - "mode": "[if(contains(parameters('natRules')[copyIndex()], 'mode'), createObject('value', parameters('natRules')[copyIndex()].mode), createObject('value', ''))]", - "type": "[if(contains(parameters('natRules')[copyIndex()], 'type'), createObject('value', parameters('natRules')[copyIndex()].type), createObject('value', ''))]" + "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#", diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep index 0b4425a9a0..09457de2bd 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep @@ -15,7 +15,7 @@ param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgatewa param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'nvngavpn' +param serviceShort string = 'nvgavpn' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' @@ -55,7 +55,9 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: false + clusterSettings:{ + clusterMode: 'activePassiveNoBgp' + } domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep new file mode 100644 index 0000000000..6270baf598 --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep new file mode 100644 index 0000000000..16fe844184 --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep new file mode 100644 index 0000000000..7d799c5c2c --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep new file mode 100644 index 0000000000..1aa9da7c34 --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep new file mode 100644 index 0000000000..ee3904f4b8 --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep index 9e5f80b30c..06f382ecb5 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep @@ -62,6 +62,9 @@ module testDeployment '../../../main.bicep' = [ 2 3 ] + clusterSettings: { + clusterMode:'activeActiveNoBgp' + } } dependsOn: [ nestedDependencies diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep index 22b116891b..600e374025 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep @@ -55,6 +55,9 @@ module testDeployment '../../../main.bicep' = [ skuName: 'ErGw1AZ' gatewayType: 'ExpressRoute' vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings:{ + clusterMode: 'activePassiveBgp' + } domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep index 346b380610..b0314fa4dc 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep @@ -72,7 +72,12 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: true + clusterSettings:{ + clusterMode: 'activeActiveBgp' + activeGatewayPipName: '${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' diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep index 7966ff4a3d..514b8429ab 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep @@ -57,6 +57,9 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw1' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings:{ + clusterMode: 'activePassiveNoBgp' + } } dependsOn: [ nestedDependencies diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep index 6ac66acfd1..4258c36c8a 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep @@ -57,7 +57,9 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: true + clusterSettings:{ + clusterMode: 'activeActiveNoBgp' + } domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep index 8a31ac21fc..e0da5f11c5 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -70,7 +70,12 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: true + 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' diff --git a/avm/res/network/virtual-network-gateway/version.json b/avm/res/network/virtual-network-gateway/version.json index 76049e1c4a..13669e6601 100644 --- a/avm/res/network/virtual-network-gateway/version.json +++ b/avm/res/network/virtual-network-gateway/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.4", "pathFilters": [ "./main.json" ] From f1d14ed950ed805b89fc2aeed75779c133a3ae31 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 20 Sep 2024 01:26:11 +0200 Subject: [PATCH 03/93] fix: static validation error and BCP error in `avm.res.dev-ops-infrastructure.pool` (#3333) ## Description This pull request fixes the following: * The static validation is now passing, fixed by rerunning the Set-AVMModule command * BCP error regarding a property/parameter that cannot be null - fixed this by making it required Tagging @matebarabas @AlexanderSehr ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.dev-ops-infrastructure.pool](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml/badge.svg?branch=johnlokerse%2Ffix-staticvalidation-mdp)](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml) | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/dev-ops-infrastructure/pool/README.md | 41 +++++++++++-------- .../dev-ops-infrastructure/pool/main.bicep | 4 +- avm/res/dev-ops-infrastructure/pool/main.json | 7 ++-- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/avm/res/dev-ops-infrastructure/pool/README.md b/avm/res/dev-ops-infrastructure/pool/README.md index 4cd888f4b4..4ea945d1ab 100644 --- a/avm/res/dev-ops-infrastructure/pool/README.md +++ b/avm/res/dev-ops-infrastructure/pool/README.md @@ -8,7 +8,7 @@ This module deploys the Managed DevOps Pool resource. - [Usage examples](#Usage-examples) - [Parameters](#Parameters) - [Outputs](#Outputs) -- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) - [Data Collection](#Data-Collection) ## Resource Types @@ -20,10 +20,6 @@ This module deploys the Managed DevOps Pool resource. | `Microsoft.DevOpsInfrastructure/pools` | [2024-04-04-preview](https://learn.microsoft.com/en-us/azure/templates) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -## Notes - -The Managed DevOps Pool resource requires external permissions in Azure DevOps. Make sure that the deployment principal has permission in Azure DevOps: [Managed DevOps Pools - Verify Azure DevOps Permissions](https://learn.microsoft.com/en-us/azure/devops/managed-devops-pools/prerequisites?view=azure-devops&tabs=azure-portal#verify-azure-devops-permissions) - ## 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. @@ -544,7 +540,6 @@ module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = {

- ## Parameters **Required parameters** @@ -739,26 +734,24 @@ The type of permission which determines which accounts are admins on the Azure D - Required: No - Type: object -**Optional parameters** +**Required parameters** | Parameter | Type | Description | | :-- | :-- | :-- | -| [`groups`](#parameter-organizationprofilepermissionprofilegroups) | array | Group email addresses. | | [`kind`](#parameter-organizationprofilepermissionprofilekind) | string | Determines who has admin permissions to the Azure DevOps pool. | -| [`users`](#parameter-organizationprofilepermissionprofileusers) | array | User email addresses. | - -### Parameter: `organizationProfile.permissionProfile.groups` -Group email addresses. +**Optional parameters** -- Required: No -- Type: array +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groups`](#parameter-organizationprofilepermissionprofilegroups) | array | Group email addresses. | +| [`users`](#parameter-organizationprofilepermissionprofileusers) | array | User email addresses. | ### Parameter: `organizationProfile.permissionProfile.kind` Determines who has admin permissions to the Azure DevOps pool. -- Required: No +- Required: Yes - Type: string - Allowed: ```Bicep @@ -769,6 +762,13 @@ Determines who has admin permissions to the Azure DevOps pool. ] ``` +### Parameter: `organizationProfile.permissionProfile.groups` + +Group email addresses. + +- Required: No +- Type: array + ### Parameter: `organizationProfile.permissionProfile.users` User email addresses. @@ -1104,6 +1104,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** @@ -1300,7 +1306,6 @@ Tags of the resource. - Required: No - Type: object - ## Outputs | Output | Type | Description | @@ -1311,9 +1316,9 @@ Tags of the resource. | `resourceId` | string | The resource ID of the Managed DevOps Pool. | | `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | -## Cross-referenced modules +## Notes -_None_ +The Managed DevOps Pool resource requires external permissions in Azure DevOps. Make sure that the deployment principal has permission in Azure DevOps: [Managed DevOps Pools - Verify Azure DevOps Permissions](https://learn.microsoft.com/en-us/azure/devops/managed-devops-pools/prerequisites?view=azure-devops&tabs=azure-portal#verify-azure-devops-permissions) ## Data Collection diff --git a/avm/res/dev-ops-infrastructure/pool/main.bicep b/avm/res/dev-ops-infrastructure/pool/main.bicep index c64d2bbce5..af61e650fe 100644 --- a/avm/res/dev-ops-infrastructure/pool/main.bicep +++ b/avm/res/dev-ops-infrastructure/pool/main.bicep @@ -292,8 +292,8 @@ type organizationProfileType = { @description('Optional. The type of permission which determines which accounts are admins on the Azure DevOps pool.') permissionProfile: { - @description('Optional. Determines who has admin permissions to the Azure DevOps pool.') - kind: ('CreatorOnly' | 'Inherit' | 'SpecificAccounts')? + @description('Required. Determines who has admin permissions to the Azure DevOps pool.') + kind: 'CreatorOnly' | 'Inherit' | 'SpecificAccounts' @description('Optional. Group email addresses.') groups: string[]? diff --git a/avm/res/dev-ops-infrastructure/pool/main.json b/avm/res/dev-ops-infrastructure/pool/main.json index 38edaf771a..ce80f4d180 100644 --- a/avm/res/dev-ops-infrastructure/pool/main.json +++ b/avm/res/dev-ops-infrastructure/pool/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9138966756251042726" + "version": "0.30.3.12046", + "templateHash": "15191897376801297199" }, "name": "Managed DevOps Pool", "description": "This module deploys the Managed DevOps Pool resource.", @@ -189,9 +189,8 @@ "Inherit", "SpecificAccounts" ], - "nullable": true, "metadata": { - "description": "Optional. Determines who has admin permissions to the Azure DevOps pool." + "description": "Required. Determines who has admin permissions to the Azure DevOps pool." } }, "groups": { From 07a059307535995bdf22a385dfebf224d3ce34ea Mon Sep 17 00:00:00 2001 From: Peter Budai Date: Fri, 20 Sep 2024 09:35:15 +0200 Subject: [PATCH 04/93] feat: Retain existing settings during deployment - `avm/res/web/site` (#3311) ## Description This commit changes the app settings deployment in order to retain existing app settings that are not defined in the Bicep file. This change allows for updating **only** the app settings that are defined in the Bicep file, while leaving the rest unchanged. As this is a change in behavior, version number has been increased. Fixes #949 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.web.site](https://github.com/peterbud/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg)](https://github.com/peterbud/bicep-registry-modules/actions/workflows/avm.res.web.site.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/web/site/README.md | 108 +++++++++++++++--- .../web/site/config--appsettings/README.md | 11 +- .../web/site/config--appsettings/main.bicep | 16 ++- .../web/site/config--appsettings/main.json | 17 ++- avm/res/web/site/main.bicep | 3 +- avm/res/web/site/main.json | 44 ++++--- .../site/slot/config--appsettings/README.md | 9 ++ .../site/slot/config--appsettings/main.bicep | 10 +- .../site/slot/config--appsettings/main.json | 11 +- avm/res/web/site/slot/main.bicep | 1 + avm/res/web/site/slot/main.json | 16 ++- .../functionApp.settings/dependencies.bicep | 21 ++++ .../e2e/functionApp.settings/main.test.bicep | 67 +++++++++++ avm/res/web/site/version.json | 2 +- 14 files changed, 284 insertions(+), 52 deletions(-) create mode 100644 avm/res/web/site/tests/e2e/functionApp.settings/dependencies.bicep create mode 100644 avm/res/web/site/tests/e2e/functionApp.settings/main.test.bicep diff --git a/avm/res/web/site/README.md b/avm/res/web/site/README.md index bc9c390cb6..12c8a2371f 100644 --- a/avm/res/web/site/README.md +++ b/avm/res/web/site/README.md @@ -21,8 +21,9 @@ This module deploys a Web or Function App. | `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.Web/sites` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites) | +| `Microsoft.Web/sites` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/basicPublishingCredentialsPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | +| `Microsoft.Web/sites/config` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/extensions` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/extensions) | | `Microsoft.Web/sites/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/hybridConnectionNamespaces/relays) | @@ -41,15 +42,16 @@ The following section provides usage examples for the module, which were used to - [Function App, using only defaults](#example-1-function-app-using-only-defaults) - [Function App, using large parameter set](#example-2-function-app-using-large-parameter-set) -- [Web App, using only defaults](#example-3-web-app-using-only-defaults) -- [Web App](#example-4-web-app) -- [WAF-aligned](#example-5-waf-aligned) -- [Web App, using only defaults](#example-6-web-app-using-only-defaults) -- [Web App, using large parameter set](#example-7-web-app-using-large-parameter-set) -- [Web App, using only defaults](#example-8-web-app-using-only-defaults) -- [Web App, using large parameter set](#example-9-web-app-using-large-parameter-set) -- [Web App](#example-10-web-app) -- [Windows Web App for Containers, using only defaults](#example-11-windows-web-app-for-containers-using-only-defaults) +- [Function App, using only defaults](#example-3-function-app-using-only-defaults) +- [Web App, using only defaults](#example-4-web-app-using-only-defaults) +- [Web App](#example-5-web-app) +- [WAF-aligned](#example-6-waf-aligned) +- [Web App, using only defaults](#example-7-web-app-using-only-defaults) +- [Web App, using large parameter set](#example-8-web-app-using-large-parameter-set) +- [Web App, using only defaults](#example-9-web-app-using-only-defaults) +- [Web App, using large parameter set](#example-10-web-app-using-large-parameter-set) +- [Web App](#example-11-web-app) +- [Windows Web App for Containers, using only defaults](#example-12-windows-web-app-for-containers-using-only-defaults) ### Example 1: _Function App, using only defaults_ @@ -515,7 +517,75 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 3: _Web App, using only defaults_ +### Example 3: _Function App, using only defaults_ + +This instance deploys the module as Function App with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module site 'br/public:avm/res/web/site:' = { + name: 'siteDeployment' + params: { + // Required parameters + kind: 'functionapp' + name: 'wsfaset001' + serverFarmResourceId: '' + // Non-required parameters + appSettingsKeyValuePairs: { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' + } + location: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "functionapp" + }, + "name": { + "value": "wsfaset001" + }, + "serverFarmResourceId": { + "value": "" + }, + // Non-required parameters + "appSettingsKeyValuePairs": { + "value": { + "AzureFunctionsJobHost__logging__logLevel__default": "Trace", + "FUNCTIONS_EXTENSION_VERSION": "~4", + "FUNCTIONS_WORKER_RUNTIME": "dotnet" + } + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 4: _Web App, using only defaults_ This instance deploys the module as a Linux Web App with the minimum set of required parameters. @@ -591,7 +661,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 4: _Web App_ +### Example 5: _Web App_ This instance deploys the module as Web App with the set of logs configuration. @@ -723,7 +793,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 5: _WAF-aligned_ +### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -865,7 +935,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 6: _Web App, using only defaults_ +### Example 7: _Web App, using only defaults_ This instance deploys the module as Web App with the minimum set of required parameters. @@ -921,7 +991,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 7: _Web App, using large parameter set_ +### Example 8: _Web App, using large parameter set_ This instance deploys the module as Web App with most of its features enabled. @@ -1389,7 +1459,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 8: _Web App, using only defaults_ +### Example 9: _Web App, using only defaults_ This instance deploys the module as a Linux Web App with the minimum set of required parameters. @@ -1445,7 +1515,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 9: _Web App, using large parameter set_ +### Example 10: _Web App, using large parameter set_ This instance deploys the module asa Linux Web App with most of its features enabled. @@ -1907,7 +1977,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 10: _Web App_ +### Example 11: _Web App_ This instance deploys the module as Web App with the set of api management configuration. @@ -2003,7 +2073,7 @@ module site 'br/public:avm/res/web/site:' = {

-### Example 11: _Windows Web App for Containers, using only defaults_ +### Example 12: _Windows Web App for Containers, using only defaults_ This instance deploys the module as a Windows based Container Web App with the minimum set of required parameters. diff --git a/avm/res/web/site/config--appsettings/README.md b/avm/res/web/site/config--appsettings/README.md index 17ff462236..db4a05b7d7 100644 --- a/avm/res/web/site/config--appsettings/README.md +++ b/avm/res/web/site/config--appsettings/README.md @@ -13,7 +13,7 @@ This module deploys a Site App Setting. | Resource Type | API Version | | :-- | :-- | -| `Microsoft.Web/sites/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | +| `Microsoft.Web/sites/config` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | ## Parameters @@ -35,6 +35,7 @@ This module deploys a Site App Setting. | :-- | :-- | :-- | | [`appInsightResourceId`](#parameter-appinsightresourceid) | string | Resource ID of the app insight to leverage for this resource. | | [`appSettingsKeyValuePairs`](#parameter-appsettingskeyvaluepairs) | object | The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING. | +| [`currentAppSettings`](#parameter-currentappsettings) | object | The current app settings. | | [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. | | [`storageAccountUseIdentityAuthentication`](#parameter-storageaccountuseidentityauthentication) | bool | If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'. | @@ -83,6 +84,14 @@ The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDas - Required: No - Type: object +### Parameter: `currentAppSettings` + +The current app settings. + +- Required: No +- Type: object +- Default: `{}` + ### Parameter: `storageAccountResourceId` Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. diff --git a/avm/res/web/site/config--appsettings/main.bicep b/avm/res/web/site/config--appsettings/main.bicep index 2f770a7774..202a2ac205 100644 --- a/avm/res/web/site/config--appsettings/main.bicep +++ b/avm/res/web/site/config--appsettings/main.bicep @@ -34,6 +34,9 @@ param appInsightResourceId string? @description('Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING.') param appSettingsKeyValuePairs object? +@description('Optional. The current app settings.') +param currentAppSettings object = {} + var azureWebJobsValues = !empty(storageAccountResourceId) && !(storageAccountUseIdentityAuthentication) ? { AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' @@ -51,9 +54,14 @@ var appInsightsValues = !empty(appInsightResourceId) } : {} -var expandedAppSettings = union(appSettingsKeyValuePairs ?? {}, azureWebJobsValues, appInsightsValues) +var expandedAppSettings = union( + currentAppSettings ?? {}, + appSettingsKeyValuePairs ?? {}, + azureWebJobsValues, + appInsightsValues +) -resource app 'Microsoft.Web/sites@2022-09-01' existing = { +resource app 'Microsoft.Web/sites@2023-12-01' existing = { name: appName } @@ -62,7 +70,7 @@ resource appInsight 'Microsoft.Insights/components@2020-02-02' existing = if (!e scope: resourceGroup(split(appInsightResourceId ?? '//', '/')[2], split(appInsightResourceId ?? '////', '/')[4]) } -resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (!empty(storageAccountResourceId)) { +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' existing = if (!empty(storageAccountResourceId)) { name: last(split(storageAccountResourceId ?? 'dummyName', '/')) scope: resourceGroup( split(storageAccountResourceId ?? '//', '/')[2], @@ -70,7 +78,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing ) } -resource appSettings 'Microsoft.Web/sites/config@2022-09-01' = { +resource appSettings 'Microsoft.Web/sites/config@2023-12-01' = { name: 'appsettings' kind: kind parent: app diff --git a/avm/res/web/site/config--appsettings/main.json b/avm/res/web/site/config--appsettings/main.json index c59a554e2a..c50105f501 100644 --- a/avm/res/web/site/config--appsettings/main.json +++ b/avm/res/web/site/config--appsettings/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "8777070640548664577" + "templateHash": "3998275265127709875" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting.", @@ -66,13 +66,20 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { "app": { "existing": true, "type": "Microsoft.Web/sites", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[parameters('appName')]" }, "appInsight": { @@ -88,17 +95,17 @@ "condition": "[not(empty(parameters('storageAccountResourceId')))]", "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-01-01", + "apiVersion": "2023-05-01", "subscriptionId": "[split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2]]", "resourceGroup": "[split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]]", "name": "[last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))]" }, "appSettings": { "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-05-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "app", "appInsight", diff --git a/avm/res/web/site/main.bicep b/avm/res/web/site/main.bicep index b7418015b6..cbd5824ec5 100644 --- a/avm/res/web/site/main.bicep +++ b/avm/res/web/site/main.bicep @@ -245,7 +245,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource app 'Microsoft.Web/sites@2022-09-01' = { +resource app 'Microsoft.Web/sites@2023-12-01' = { name: name location: location kind: kind @@ -294,6 +294,7 @@ module app_appsettings 'config--appsettings/main.bicep' = if (!empty(appSettings storageAccountUseIdentityAuthentication: storageAccountUseIdentityAuthentication appInsightResourceId: appInsightResourceId appSettingsKeyValuePairs: appSettingsKeyValuePairs + currentAppSettings: !empty(app.id) ? list('${app.id}/config/appsettings', '2023-12-01').properties : {} } } diff --git a/avm/res/web/site/main.json b/avm/res/web/site/main.json index e6eccb3688..d3577e551f 100644 --- a/avm/res/web/site/main.json +++ b/avm/res/web/site/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "7320044434284742277" + "templateHash": "4626438010490721609" }, "name": "Web/Function Apps", "description": "This module deploys a Web or Function App.", @@ -860,7 +860,7 @@ }, "app": { "type": "Microsoft.Web/sites", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -998,7 +998,8 @@ }, "appSettingsKeyValuePairs": { "value": "[parameters('appSettingsKeyValuePairs')]" - } + }, + "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites', parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites', parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1008,7 +1009,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "8777070640548664577" + "templateHash": "3998275265127709875" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting.", @@ -1068,13 +1069,20 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { "app": { "existing": true, "type": "Microsoft.Web/sites", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[parameters('appName')]" }, "appInsight": { @@ -1090,17 +1098,17 @@ "condition": "[not(empty(parameters('storageAccountResourceId')))]", "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-01-01", + "apiVersion": "2023-05-01", "subscriptionId": "[split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2]]", "resourceGroup": "[split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]]", "name": "[last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))]" }, "appSettings": { "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-05-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "app", "appInsight", @@ -1677,7 +1685,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "15729572124587777376" + "templateHash": "13282951347078727812" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -2639,7 +2647,8 @@ }, "appSettingsKeyValuePairs": { "value": "[parameters('appSettingsKeyValuePairs')]" - } + }, + "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2649,7 +2658,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "7111332561212908044" + "templateHash": "9363357518124041583" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -2715,6 +2724,13 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { @@ -2756,7 +2772,7 @@ "apiVersion": "2022-09-01", "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "appInsight", "app::slot", @@ -5111,7 +5127,7 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('app', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('app', '2023-12-01', 'full'), 'identity'), 'principalId'), '')]" }, "slotSystemAssignedMIPrincipalIds": { "type": "array", @@ -5128,7 +5144,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('app', '2022-09-01', 'full').location]" + "value": "[reference('app', '2023-12-01', 'full').location]" }, "defaultHostname": { "type": "string", diff --git a/avm/res/web/site/slot/config--appsettings/README.md b/avm/res/web/site/slot/config--appsettings/README.md index 6be3108fe1..a4eaf7b5e3 100644 --- a/avm/res/web/site/slot/config--appsettings/README.md +++ b/avm/res/web/site/slot/config--appsettings/README.md @@ -36,6 +36,7 @@ This module deploys a Site Slot App Setting. | :-- | :-- | :-- | | [`appInsightResourceId`](#parameter-appinsightresourceid) | string | Resource ID of the app insight to leverage for this resource. | | [`appSettingsKeyValuePairs`](#parameter-appsettingskeyvaluepairs) | object | The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING. | +| [`currentAppSettings`](#parameter-currentappsettings) | object | The current app settings. | | [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. | | [`storageAccountUseIdentityAuthentication`](#parameter-storageaccountuseidentityauthentication) | bool | If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'. | @@ -91,6 +92,14 @@ The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDas - Required: No - Type: object +### Parameter: `currentAppSettings` + +The current app settings. + +- Required: No +- Type: object +- Default: `{}` + ### Parameter: `storageAccountResourceId` Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. diff --git a/avm/res/web/site/slot/config--appsettings/main.bicep b/avm/res/web/site/slot/config--appsettings/main.bicep index 74095161a8..2fbe7b81d4 100644 --- a/avm/res/web/site/slot/config--appsettings/main.bicep +++ b/avm/res/web/site/slot/config--appsettings/main.bicep @@ -37,6 +37,9 @@ param appInsightResourceId string? @description('Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING.') param appSettingsKeyValuePairs object? +@description('Optional. The current app settings.') +param currentAppSettings object = {} + var azureWebJobsValues = !empty(storageAccountResourceId) && !(storageAccountUseIdentityAuthentication) ? { AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' @@ -54,7 +57,12 @@ var appInsightsValues = !empty(appInsightResourceId) } : {} -var expandedAppSettings = union(appSettingsKeyValuePairs ?? {}, azureWebJobsValues, appInsightsValues) +var expandedAppSettings = union( + currentAppSettings ?? {}, + appSettingsKeyValuePairs ?? {}, + azureWebJobsValues, + appInsightsValues +) resource app 'Microsoft.Web/sites@2022-09-01' existing = { name: appName diff --git a/avm/res/web/site/slot/config--appsettings/main.json b/avm/res/web/site/slot/config--appsettings/main.json index 48ed22304b..af2de6024a 100644 --- a/avm/res/web/site/slot/config--appsettings/main.json +++ b/avm/res/web/site/slot/config--appsettings/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "7111332561212908044" + "templateHash": "9363357518124041583" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -72,6 +72,13 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { @@ -113,7 +120,7 @@ "apiVersion": "2022-09-01", "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "appInsight", "app::slot", diff --git a/avm/res/web/site/slot/main.bicep b/avm/res/web/site/slot/main.bicep index b871bf0960..95b2e0eff7 100644 --- a/avm/res/web/site/slot/main.bicep +++ b/avm/res/web/site/slot/main.bicep @@ -264,6 +264,7 @@ module slot_appsettings 'config--appsettings/main.bicep' = if (!empty(appSetting storageAccountUseIdentityAuthentication: storageAccountUseIdentityAuthentication appInsightResourceId: appInsightResourceId appSettingsKeyValuePairs: appSettingsKeyValuePairs + currentAppSettings: !empty(slot.id) ? list('${slot.id}/config/appsettings', '2023-12-01').properties : {} } } diff --git a/avm/res/web/site/slot/main.json b/avm/res/web/site/slot/main.json index 8f8f81e34a..3120546cad 100644 --- a/avm/res/web/site/slot/main.json +++ b/avm/res/web/site/slot/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "15729572124587777376" + "templateHash": "13282951347078727812" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -968,7 +968,8 @@ }, "appSettingsKeyValuePairs": { "value": "[parameters('appSettingsKeyValuePairs')]" - } + }, + "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -978,7 +979,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "7111332561212908044" + "templateHash": "9363357518124041583" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -1044,6 +1045,13 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { @@ -1085,7 +1093,7 @@ "apiVersion": "2022-09-01", "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "appInsight", "app::slot", diff --git a/avm/res/web/site/tests/e2e/functionApp.settings/dependencies.bicep b/avm/res/web/site/tests/e2e/functionApp.settings/dependencies.bicep new file mode 100644 index 0000000000..dd34e10b1c --- /dev/null +++ b/avm/res/web/site/tests/e2e/functionApp.settings/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Server Farm to create.') +param serverFarmName string + +resource serverFarm 'Microsoft.Web/serverfarms@2022-03-01' = { + name: serverFarmName + location: location + sku: { + name: 'S1' + tier: 'Standard' + size: 'S1' + family: 'S' + capacity: 1 + } + properties: {} +} + +@description('The resource ID of the created Server Farm.') +output serverFarmResourceId string = serverFarm.id diff --git a/avm/res/web/site/tests/e2e/functionApp.settings/main.test.bicep b/avm/res/web/site/tests/e2e/functionApp.settings/main.test.bicep new file mode 100644 index 0000000000..a62f7217a1 --- /dev/null +++ b/avm/res/web/site/tests/e2e/functionApp.settings/main.test.bicep @@ -0,0 +1,67 @@ +targetScope = 'subscription' + +metadata name = 'Function App, using only defaults' +metadata description = 'This instance deploys the module as Function App 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}-web.sites-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'wsfaset' + +@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: { + serverFarmName: 'dep-${namePrefix}-sf-${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 + kind: 'functionapp' + serverFarmResourceId: nestedDependencies.outputs.serverFarmResourceId + appSettingsKeyValuePairs: { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/res/web/site/version.json b/avm/res/web/site/version.json index 0f81d22abc..b8b30a0125 100644 --- a/avm/res/web/site/version.json +++ b/avm/res/web/site/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.8", + "version": "0.9", "pathFilters": [ "./main.json" ] From 73fc84f9a61c1427b1f4947805d7d41cdaaacb74 Mon Sep 17 00:00:00 2001 From: Fabio Masciotra Date: Mon, 23 Sep 2024 13:35:56 +0200 Subject: [PATCH 05/93] fix: module `avm/res/network/nat-gateway` (#3341) ## Description added a test case about the use of an existing Public IP address Closes #2378 ## Pipeline Reference [![avm.res.network.nat-gateway](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml/badge.svg?branch=natgw)](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml) | Pipeline | | -------- | | | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/network/nat-gateway/README.md | 69 +++++++++++++++++-- avm/res/network/nat-gateway/main.bicep | 4 +- avm/res/network/nat-gateway/main.json | 20 +++--- .../tests/e2e/existingPip/dependencies.bicep | 25 +++++++ .../tests/e2e/existingPip/main.test.bicep | 61 ++++++++++++++++ 5 files changed, 163 insertions(+), 16 deletions(-) create mode 100644 avm/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep create mode 100644 avm/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep diff --git a/avm/res/network/nat-gateway/README.md b/avm/res/network/nat-gateway/README.md index 8c6358ff0c..d12c7b26f7 100644 --- a/avm/res/network/nat-gateway/README.md +++ b/avm/res/network/nat-gateway/README.md @@ -31,9 +31,10 @@ The following section provides usage examples for the module, which were used to >**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 large parameter set](#example-2-using-large-parameter-set) -- [Combine a generated and provided Public IP Prefix](#example-3-combine-a-generated-and-provided-public-ip-prefix) -- [WAF-aligned](#example-4-waf-aligned) +- [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_ @@ -87,7 +88,63 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-### Example 2: _Using large parameter set_ +### 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 Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nngepip001" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIpResourceIds": { + "value": "" + } + } +} +``` + +
+

+ +### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -287,7 +344,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-### Example 3: _Combine a generated and provided Public IP Prefix_ +### 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. @@ -359,7 +416,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-### Example 4: _WAF-aligned_ +### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. diff --git a/avm/res/network/nat-gateway/main.bicep b/avm/res/network/nat-gateway/main.bicep index 8836c815fe..f576caedd5 100644 --- a/avm/res/network/nat-gateway/main.bicep +++ b/avm/res/network/nat-gateway/main.bicep @@ -99,7 +99,7 @@ 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: contains(publicIPAddressObject, 'name') ? publicIPAddressObject.name : '${name}-pip' + name: publicIPAddressObject.?name ?? '${name}-pip' location: location lock: publicIPAddressObject.?lock ?? lock diagnosticSettings: publicIPAddressObject.?diagnosticSettings @@ -133,7 +133,7 @@ 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: contains(publicIPPrefixObject, 'name') ? publicIPPrefixObject.name : '${name}-pip' + name: publicIPPrefixObject.?name ?? '${name}-pip' location: location lock: publicIPPrefixObject.?lock ?? lock prefixLength: publicIPPrefixObject.prefixLength diff --git a/avm/res/network/nat-gateway/main.json b/avm/res/network/nat-gateway/main.json index 414a6e0129..588a626b30 100644 --- a/avm/res/network/nat-gateway/main.json +++ b/avm/res/network/nat-gateway/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3430947452943320440" + "version": "0.30.3.12046", + "templateHash": "16462612640291787003" }, "name": "NAT Gateways", "description": "This module deploys a NAT Gateway.", @@ -308,7 +308,9 @@ }, "mode": "Incremental", "parameters": { - "name": "[if(contains(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'name'), createObject('value', coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()].name), createObject('value', format('{0}-pip', parameters('name'))))]", + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'name'), format('{0}-pip', parameters('name')))]" + }, "location": { "value": "[parameters('location')]" }, @@ -1004,8 +1006,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15040145942768763519" + "version": "0.30.3.12046", + "templateHash": "9121047532434826411" } }, "parameters": { @@ -1050,7 +1052,9 @@ }, "mode": "Incremental", "parameters": { - "name": "[if(contains(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'name'), createObject('value', coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()].name), createObject('value', format('{0}-pip', parameters('name'))))]", + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'name'), format('{0}-pip', parameters('name')))]" + }, "location": { "value": "[parameters('location')]" }, @@ -1416,8 +1420,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15040145942768763519" + "version": "0.30.3.12046", + "templateHash": "9121047532434826411" } }, "parameters": { diff --git a/avm/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep b/avm/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep new file mode 100644 index 0000000000..d12b008b0c --- /dev/null +++ b/avm/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/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep b/avm/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep new file mode 100644 index 0000000000..1b13848208 --- /dev/null +++ b/avm/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] + } + } +] From 201c378a69ca7cf115b71a900091e708ba00c909 Mon Sep 17 00:00:00 2001 From: Chinedum Echeta <60179183+cecheta@users.noreply.github.com> Date: Tue, 24 Sep 2024 00:34:43 -0700 Subject: [PATCH 06/93] feat: `avm/ptn/ai-platform/baseline` Change identities of AI workspaces (#3345) ## Description This PR changes the managed identities of both the workspace project and hub * The workspace hub no longer creates a user assigned identity, but instead expects the name of an already existing UAI to be passed in. This is because there is now validation when creating a workspace that it should have permissions to approve private endpoint connections * The workspace project now only uses a system assigned identity, as it is not possible to authenticate with a private container registry using a user assigned identity ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.ai-platform.baseline](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml/badge.svg?branch=identity)](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [x] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/ai-platform/baseline/README.md | 56 +--- avm/ptn/ai-platform/baseline/main.bicep | 286 ++++++---------- avm/ptn/ai-platform/baseline/main.json | 309 +++--------------- .../baseline/tests/e2e/max/dependencies.bicep | 11 + .../baseline/tests/e2e/max/main.test.bicep | 6 +- .../tests/e2e/waf-aligned/dependencies.bicep | 23 ++ .../tests/e2e/waf-aligned/main.test.bicep | 2 + avm/ptn/ai-platform/baseline/version.json | 2 +- 8 files changed, 200 insertions(+), 495 deletions(-) diff --git a/avm/ptn/ai-platform/baseline/README.md b/avm/ptn/ai-platform/baseline/README.md index 45718c8a77..dfaf48f4a5 100644 --- a/avm/ptn/ai-platform/baseline/README.md +++ b/avm/ptn/ai-platform/baseline/README.md @@ -38,7 +38,6 @@ By integrating with Microsoft Entra ID for secure identity management and utiliz | `Microsoft.MachineLearningServices/workspaces` | [2024-04-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01-preview/workspaces) | | `Microsoft.MachineLearningServices/workspaces/computes` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2022-10-01/workspaces/computes) | | `Microsoft.Maintenance/configurationAssignments` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Maintenance/2023-04-01/configurationAssignments) | -| `Microsoft.ManagedIdentity/userAssignedIdentities` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities) | | `Microsoft.Network/bastionHosts` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-11-01/bastionHosts) | | `Microsoft.Network/networkInterfaces` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkInterfaces) | | `Microsoft.Network/networkSecurityGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/networkSecurityGroups) | @@ -54,8 +53,8 @@ By integrating with Microsoft Entra ID for secure identity management and utiliz | `Microsoft.Network/privateDnsZones/virtualNetworkLinks` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/virtualNetworkLinks) | | `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | -| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | | `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | | `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | @@ -185,10 +184,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { logAnalyticsConfiguration: { name: 'log-aipbmax' } - managedIdentityConfiguration: { - hubName: 'id-hub-aipbmax' - projectName: 'id-project-aipbmax' - } + managedIdentityName: '' storageAccountConfiguration: { allowSharedKeyAccess: true name: 'staipbmax' @@ -321,11 +317,8 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { "name": "log-aipbmax" } }, - "managedIdentityConfiguration": { - "value": { - "hubName": "id-hub-aipbmax", - "projectName": "id-project-aipbmax" - } + "managedIdentityName": { + "value": "" }, "storageAccountConfiguration": { "value": { @@ -544,6 +537,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { // Required parameters name: '' // Non-required parameters + managedIdentityName: '' tags: { Env: 'test' 'hidden-title': 'This is visible in the resource name' @@ -591,6 +585,9 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { "value": "" }, // Non-required parameters + "managedIdentityName": { + "value": "" + }, "tags": { "value": { "Env": "test", @@ -649,7 +646,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { | [`keyVaultConfiguration`](#parameter-keyvaultconfiguration) | object | Configuration for the key vault. | | [`location`](#parameter-location) | string | Location for all Resources. | | [`logAnalyticsConfiguration`](#parameter-loganalyticsconfiguration) | object | Configuration for the Log Analytics workspace. | -| [`managedIdentityConfiguration`](#parameter-managedidentityconfiguration) | object | Configuration for the user-assigned managed identities. | +| [`managedIdentityName`](#parameter-managedidentityname) | string | The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity. | | [`storageAccountConfiguration`](#parameter-storageaccountconfiguration) | object | Configuration for the storage account. | | [`tags`](#parameter-tags) | object | Resource tags. | | [`virtualMachineConfiguration`](#parameter-virtualmachineconfiguration) | secureObject | Configuration for the virtual machine. | @@ -889,30 +886,9 @@ The name of the Log Analytics workspace. - Required: No - Type: string -### Parameter: `managedIdentityConfiguration` - -Configuration for the user-assigned managed identities. - -- Required: No -- Type: object - -**Optional parameters** - -| Parameter | Type | Description | -| :-- | :-- | :-- | -| [`hubName`](#parameter-managedidentityconfigurationhubname) | string | The name of the workspace hub user-assigned managed identity. | -| [`projectName`](#parameter-managedidentityconfigurationprojectname) | string | The name of the workspace project user-assigned managed identity. | - -### Parameter: `managedIdentityConfiguration.hubName` - -The name of the workspace hub user-assigned managed identity. - -- Required: No -- Type: string - -### Parameter: `managedIdentityConfiguration.projectName` +### Parameter: `managedIdentityName` -The name of the workspace project user-assigned managed identity. +The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity. - Required: No - Type: string @@ -1144,14 +1120,6 @@ The name of the AI Studio workspace project. | `location` | string | The location the module was deployed to. | | `logAnalyticsWorkspaceName` | string | The name of the log analytics workspace. | | `logAnalyticsWorkspaceResourceId` | string | The resource ID of the log analytics workspace. | -| `managedIdentityHubClientId` | string | The client ID of the workspace hub user assigned managed identity. | -| `managedIdentityHubName` | string | The name of the workspace hub user assigned managed identity. | -| `managedIdentityHubPrincipalId` | string | The principal ID of the workspace hub user assigned managed identity. | -| `managedIdentityHubResourceId` | string | The resource ID of the workspace hub user assigned managed identity. | -| `managedIdentityProjectClientId` | string | The client ID of the workspace project user assigned managed identity. | -| `managedIdentityProjectName` | string | The name of the workspace project user assigned managed identity. | -| `managedIdentityProjectPrincipalId` | string | The principal ID of the workspace project user assigned managed identity. | -| `managedIdentityProjectResourceId` | string | The resource ID of the workspace project user assigned managed identity. | | `resourceGroupName` | string | The name of the resource group the module was deployed to. | | `storageAccountName` | string | The name of the storage account. | | `storageAccountResourceId` | string | The resource ID of the storage account. | @@ -1161,8 +1129,10 @@ The name of the AI Studio workspace project. | `virtualNetworkResourceId` | string | The resource ID of the virtual network. | | `virtualNetworkSubnetName` | string | The name of the subnet in the virtual network. | | `virtualNetworkSubnetResourceId` | string | The resource ID of the subnet in the virtual network. | +| `workspaceHubManagedIdentityPrincipalId` | string | The principal ID of the workspace hub system assigned identity, if applicable. | | `workspaceHubName` | string | The name of the workspace hub. | | `workspaceHubResourceId` | string | The resource ID of the workspace hub. | +| `workspaceProjectManagedIdentityPrincipalId` | string | The principal ID of the workspace project system assigned identity. | | `workspaceProjectName` | string | The name of the workspace project. | | `workspaceProjectResourceId` | string | The resource ID of the workspace project. | diff --git a/avm/ptn/ai-platform/baseline/main.bicep b/avm/ptn/ai-platform/baseline/main.bicep index d3095c0f79..29b505f083 100644 --- a/avm/ptn/ai-platform/baseline/main.bicep +++ b/avm/ptn/ai-platform/baseline/main.bicep @@ -17,8 +17,8 @@ param tags object? @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -@description('Optional. Configuration for the user-assigned managed identities.') -param managedIdentityConfiguration managedIdentityConfigurationType +@description('Optional. The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity.') +param managedIdentityName string? @description('Optional. Configuration for the Log Analytics workspace.') param logAnalyticsConfiguration logAnalyticsConfigurationType @@ -120,13 +120,15 @@ module workspaceHub_privateDnsZones 'br/public:avm/res/network/private-dns-zone: virtualNetworkResourceId: virtualNetwork.id } ] - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null } } ] @@ -278,16 +280,8 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.5.3' = if (cr } } -resource managedIdentityHub 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { - name: managedIdentityConfiguration.?hubName ?? 'id-hub-${name}' - location: location - tags: tags -} - -resource managedIdentityProject 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { - name: managedIdentityConfiguration.?projectName ?? 'id-project-${name}' - location: location - tags: tags +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (managedIdentityName != null) { + name: managedIdentityName ?? 'null' } resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { @@ -296,14 +290,14 @@ resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09 tags: tags } -resource resourceGroup_roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { +resource resourceGroup_roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (managedIdentityName != null) { name: guid(resourceGroup().id, name) properties: { roleDefinitionId: subscriptionResourceId( 'Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader ) - principalId: managedIdentityHub.properties.principalId + principalId: userAssignedIdentity.properties.principalId principalType: 'ServicePrincipal' } } @@ -324,28 +318,20 @@ module keyVault 'br/public:avm/res/key-vault/vault:0.6.2' = { } publicNetworkAccess: 'Disabled' enablePurgeProtection: keyVaultConfiguration.?enablePurgeProtection ?? true - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Key Vault Administrator' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Key Vault Administrator' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Key Vault Administrator' + principalType: 'ServicePrincipal' + } + ] + : null diagnosticSettings: [ { workspaceResourceId: logAnalyticsWorkspace.id @@ -385,48 +371,25 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.11.0' = { privateDnsZoneResourceIds: [resourceId('Microsoft.Network/privateDnsZones', zone.key)] }) : null - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Reader' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Storage Account Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Storage Table Data Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Privileged Contributor - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Privileged Contributor - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Privileged Contributor + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } @@ -444,28 +407,20 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.3.1' = networkRuleBypassOptions: 'AzureServices' zoneRedundancy: 'Enabled' trustPolicyStatus: containerRegistryConfiguration.?trustPolicyStatus ?? 'enabled' - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'AcrPull' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'AcrPull' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'AcrPull' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } } @@ -478,18 +433,15 @@ module applicationInsights 'br/public:avm/res/insights/component:0.3.1' = { kind: 'web' enableTelemetry: enableTelemetry workspaceResourceId: logAnalyticsWorkspace.id - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } } @@ -509,12 +461,14 @@ module workspaceHub 'br/public:avm/res/machine-learning-services/workspace:0.5.0 workspaceHubConfig: { defaultWorkspaceResourceGroup: resourceGroup().id } - managedIdentities: { - userAssignedResourceIds: [ - managedIdentityHub.id - ] - } - primaryUserAssignedIdentity: managedIdentityHub.id + managedIdentities: managedIdentityName != null + ? { + userAssignedResourceIds: [ + userAssignedIdentity.id + ] + } + : null + primaryUserAssignedIdentity: managedIdentityName != null ? userAssignedIdentity.id : null computes: workspaceConfiguration.?computes managedNetworkSettings: { isolationMode: workspaceConfiguration.?networkIsolationMode ?? 'AllowInternetOutbound' @@ -537,19 +491,22 @@ module workspaceHub 'br/public:avm/res/machine-learning-services/workspace:0.5.0 ] : null systemDatastoresAuthMode: 'identity' - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } dependsOn: workspaceHub_privateDnsZones } +// The workspace project uses a system assigned managed identity, so it can authenticate with the container registry module workspaceProject 'br/public:avm/res/machine-learning-services/workspace:0.5.0' = { name: '${uniqueString(deployment().name, location)}-project' params: { @@ -559,24 +516,15 @@ module workspaceProject 'br/public:avm/res/machine-learning-services/workspace:0 enableTelemetry: enableTelemetry kind: 'Project' hubResourceId: workspaceHub.outputs.resourceId - managedIdentities: { - userAssignedResourceIds: [ - managedIdentityProject.id - ] - } - primaryUserAssignedIdentity: managedIdentityProject.id - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } } @@ -612,30 +560,6 @@ output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id @description('The name of the log analytics workspace.') output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name -@description('The resource ID of the workspace hub user assigned managed identity.') -output managedIdentityHubResourceId string = managedIdentityHub.id - -@description('The name of the workspace hub user assigned managed identity.') -output managedIdentityHubName string = managedIdentityHub.name - -@description('The principal ID of the workspace hub user assigned managed identity.') -output managedIdentityHubPrincipalId string = managedIdentityHub.properties.principalId - -@description('The client ID of the workspace hub user assigned managed identity.') -output managedIdentityHubClientId string = managedIdentityHub.properties.clientId - -@description('The resource ID of the workspace project user assigned managed identity.') -output managedIdentityProjectResourceId string = managedIdentityProject.id - -@description('The name of the workspace project user assigned managed identity.') -output managedIdentityProjectName string = managedIdentityProject.name - -@description('The principal ID of the workspace project user assigned managed identity.') -output managedIdentityProjectPrincipalId string = managedIdentityProject.properties.principalId - -@description('The client ID of the workspace project user assigned managed identity.') -output managedIdentityProjectClientId string = managedIdentityProject.properties.clientId - @description('The resource ID of the key vault.') output keyVaultResourceId string = keyVault.outputs.resourceId @@ -663,6 +587,12 @@ output workspaceHubResourceId string = workspaceHub.outputs.resourceId @description('The name of the workspace hub.') output workspaceHubName string = workspaceHub.outputs.name +@description('The principal ID of the workspace hub system assigned identity, if applicable.') +output workspaceHubManagedIdentityPrincipalId string = workspaceHub.outputs.systemAssignedMIPrincipalId + +@description('The principal ID of the workspace project system assigned identity.') +output workspaceProjectManagedIdentityPrincipalId string = workspaceProject.outputs.systemAssignedMIPrincipalId + @description('The resource ID of the workspace project.') output workspaceProjectResourceId string = workspaceProject.outputs.resourceId @@ -697,14 +627,6 @@ output virtualMachineName string = createVirtualMachine ? virtualMachine.outputs // Definitions // // ================ // -type managedIdentityConfigurationType = { - @description('Optional. The name of the workspace hub user-assigned managed identity.') - hubName: string? - - @description('Optional. The name of the workspace project user-assigned managed identity.') - projectName: string? -}? - type logAnalyticsConfigurationType = { @description('Optional. The name of the Log Analytics workspace.') name: string? diff --git a/avm/ptn/ai-platform/baseline/main.json b/avm/ptn/ai-platform/baseline/main.json index 4fe65a2d83..a6eafbcbbd 100644 --- a/avm/ptn/ai-platform/baseline/main.json +++ b/avm/ptn/ai-platform/baseline/main.json @@ -5,34 +5,14 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2263138345896714301" + "version": "0.30.3.12046", + "templateHash": "12442663604053803236" }, "name": "AI Platform Baseline", "description": "This module provides a secure and scalable environment for deploying AI applications on Azure.\nThe module encompasses all essential components required for building, managing, and observing AI solutions, including a machine learning workspace, observability tools, and necessary data management services.\nBy integrating with Microsoft Entra ID for secure identity management and utilizing private endpoints for services like Key Vault and Blob Storage, the module ensures secure communication and data access.", "owner": "Azure/module-maintainers" }, "definitions": { - "managedIdentityConfigurationType": { - "type": "object", - "properties": { - "hubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the workspace hub user-assigned managed identity." - } - }, - "projectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the workspace project user-assigned managed identity." - } - } - }, - "nullable": true - }, "logAnalyticsConfigurationType": { "type": "object", "properties": { @@ -776,10 +756,11 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "managedIdentityConfiguration": { - "$ref": "#/definitions/managedIdentityConfigurationType", + "managedIdentityName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Configuration for the user-assigned managed identities." + "description": "Optional. The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity." } }, "logAnalyticsConfiguration": { @@ -919,19 +900,12 @@ } } }, - "managedIdentityHub": { + "userAssignedIdentity": { + "condition": "[not(equals(parameters('managedIdentityName'), null()))]", + "existing": true, "type": "Microsoft.ManagedIdentity/userAssignedIdentities", "apiVersion": "2023-01-31", - "name": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name')))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "managedIdentityProject": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name')))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" + "name": "[coalesce(parameters('managedIdentityName'), 'null')]" }, "logAnalyticsWorkspace": { "type": "Microsoft.OperationalInsights/workspaces", @@ -941,16 +915,17 @@ "tags": "[parameters('tags')]" }, "resourceGroup_roleAssignment": { + "condition": "[not(equals(parameters('managedIdentityName'), null()))]", "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "name": "[guid(resourceGroup().id, parameters('name'))]", "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "principalId": "[reference('managedIdentityHub').principalId]", + "principalId": "[reference('userAssignedIdentity').principalId]", "principalType": "ServicePrincipal" }, "dependsOn": [ - "managedIdentityHub" + "userAssignedIdentity" ] }, "storageAccount_privateDnsZones": { @@ -3860,15 +3835,7 @@ } ] }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - } + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -6723,7 +6690,7 @@ } }, "dependsOn": [ - "managedIdentityHub", + "userAssignedIdentity", "virtualNetwork" ] }, @@ -14047,30 +14014,7 @@ "enablePurgeProtection": { "value": "[coalesce(tryGet(parameters('keyVaultConfiguration'), 'enablePurgeProtection'), true())]" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Key Vault Administrator", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Key Vault Administrator", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Key Vault Administrator', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "diagnosticSettings": { "value": [ { @@ -16818,8 +16762,7 @@ }, "dependsOn": [ "logAnalyticsWorkspace", - "managedIdentityHub", - "managedIdentityProject" + "userAssignedIdentity" ] }, "storageAccount": { @@ -16863,50 +16806,7 @@ } }, "privateEndpoints": "[if(not(equals(variables('subnetResourceId'), null())), createObject('value', map(items(variables('storagePrivateDnsZones')), lambda('zone', createObject('name', format('pep-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'service', lambdaVariables('zone').value, 'subnetResourceId', coalesce(variables('subnetResourceId'), ''), 'privateDnsZoneResourceIds', createArray(resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone').key)))))), createObject('value', null()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Storage Account Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Storage Table Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "69566ab7-960f-475b-8e7c-b3118f30c6bd", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "69566ab7-960f-475b-8e7c-b3118f30c6bd", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Storage Blob Data Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', '69566ab7-960f-475b-8e7c-b3118f30c6bd', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -21570,9 +21470,8 @@ }, "dependsOn": [ "virtualNetwork::defaultSubnet", - "managedIdentityHub", - "managedIdentityProject", - "storageAccount_privateDnsZones" + "storageAccount_privateDnsZones", + "userAssignedIdentity" ] }, "containerRegistry": { @@ -21609,30 +21508,7 @@ "trustPolicyStatus": { "value": "[coalesce(tryGet(parameters('containerRegistryConfiguration'), 'trustPolicyStatus'), 'enabled')]" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "AcrPull", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "AcrPull", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'AcrPull', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -23754,8 +23630,7 @@ } }, "dependsOn": [ - "managedIdentityHub", - "managedIdentityProject" + "userAssignedIdentity" ] }, "applicationInsights": { @@ -23783,20 +23658,7 @@ "workspaceResourceId": { "value": "[resourceId('Microsoft.OperationalInsights/workspaces', coalesce(tryGet(parameters('logAnalyticsConfiguration'), 'name'), format('log-{0}', parameters('name'))))]" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -24397,8 +24259,7 @@ }, "dependsOn": [ "logAnalyticsWorkspace", - "managedIdentityHub", - "managedIdentityProject" + "userAssignedIdentity" ] }, "workspaceHub": { @@ -24443,16 +24304,8 @@ "defaultWorkspaceResourceGroup": "[resourceGroup().id]" } }, - "managedIdentities": { - "value": { - "userAssignedResourceIds": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name'))))]" - ] - } - }, - "primaryUserAssignedIdentity": { - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name'))))]" - }, + "managedIdentities": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createObject('userAssignedResourceIds', createArray(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(parameters('managedIdentityName'), 'null'))))), createObject('value', null()))]", + "primaryUserAssignedIdentity": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(parameters('managedIdentityName'), 'null'))), createObject('value', null()))]", "computes": { "value": "[tryGet(parameters('workspaceConfiguration'), 'computes')]" }, @@ -24466,15 +24319,7 @@ "systemDatastoresAuthMode": { "value": "identity" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -26720,8 +26565,8 @@ "containerRegistry", "virtualNetwork::defaultSubnet", "keyVault", - "managedIdentityHub", "storageAccount", + "userAssignedIdentity", "workspaceHub_privateDnsZones" ] }, @@ -26753,30 +26598,7 @@ "hubResourceId": { "value": "[reference('workspaceHub').outputs.resourceId.value]" }, - "managedIdentities": { - "value": { - "userAssignedResourceIds": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name'))))]" - ] - } - }, - "primaryUserAssignedIdentity": { - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name'))))]" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -29018,8 +28840,7 @@ } }, "dependsOn": [ - "managedIdentityHub", - "managedIdentityProject", + "userAssignedIdentity", "workspaceHub" ] } @@ -29088,62 +28909,6 @@ }, "value": "[coalesce(tryGet(parameters('logAnalyticsConfiguration'), 'name'), format('log-{0}', parameters('name')))]" }, - "managedIdentityHubResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the workspace hub user assigned managed identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name'))))]" - }, - "managedIdentityHubName": { - "type": "string", - "metadata": { - "description": "The name of the workspace hub user assigned managed identity." - }, - "value": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name')))]" - }, - "managedIdentityHubPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the workspace hub user assigned managed identity." - }, - "value": "[reference('managedIdentityHub').principalId]" - }, - "managedIdentityHubClientId": { - "type": "string", - "metadata": { - "description": "The client ID of the workspace hub user assigned managed identity." - }, - "value": "[reference('managedIdentityHub').clientId]" - }, - "managedIdentityProjectResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the workspace project user assigned managed identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name'))))]" - }, - "managedIdentityProjectName": { - "type": "string", - "metadata": { - "description": "The name of the workspace project user assigned managed identity." - }, - "value": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name')))]" - }, - "managedIdentityProjectPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the workspace project user assigned managed identity." - }, - "value": "[reference('managedIdentityProject').principalId]" - }, - "managedIdentityProjectClientId": { - "type": "string", - "metadata": { - "description": "The client ID of the workspace project user assigned managed identity." - }, - "value": "[reference('managedIdentityProject').clientId]" - }, "keyVaultResourceId": { "type": "string", "metadata": { @@ -29207,6 +28972,20 @@ }, "value": "[reference('workspaceHub').outputs.name.value]" }, + "workspaceHubManagedIdentityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the workspace hub system assigned identity, if applicable." + }, + "value": "[reference('workspaceHub').outputs.systemAssignedMIPrincipalId.value]" + }, + "workspaceProjectManagedIdentityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the workspace project system assigned identity." + }, + "value": "[reference('workspaceProject').outputs.systemAssignedMIPrincipalId.value]" + }, "workspaceProjectResourceId": { "type": "string", "metadata": { diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep index d2ea57bb6a..1ce964acc0 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep @@ -4,6 +4,9 @@ param location string = resourceGroup().location @description('Required. The name of the Storage Account to create.') param storageAccountName string +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + @description('Required. The name of the Maintenance Configuration to create.') param maintenanceConfigurationName string @@ -13,6 +16,11 @@ 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 storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { name: storageAccountName location: location @@ -196,6 +204,9 @@ resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@20 @description('The resource ID of the created Storage Account.') output storageAccountResourceId string = storageAccount.id +@description('The name of the created Managed Identity.') +output managedIdentityName string = managedIdentity.name + @description('The resource ID of the created Network Security Group.') output networkSecurityGroupResourceId string = networkSecurityGroup.id diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep index 240496050a..a8beac49bf 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep @@ -44,6 +44,7 @@ module nestedDependencies 'dependencies.bicep' = { params: { location: resourceLocation storageAccountName: 'dep${namePrefix}st${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' maintenanceConfigurationName: 'dep-${namePrefix}-mc-${serviceShort}' networkSecurityGroupName: 'dep${namePrefix}nsg${serviceShort}' networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' @@ -61,10 +62,7 @@ module testDeployment '../../../main.bicep' = [ name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}' - managedIdentityConfiguration: { - hubName: '${namePrefix}-id-hub-${serviceShort}' - projectName: '${namePrefix}-id-project-${serviceShort}' - } + managedIdentityName: nestedDependencies.outputs.managedIdentityName logAnalyticsConfiguration: { name: '${namePrefix}-log-${serviceShort}' } diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep index 299d71ad37..fbb0fe92d4 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep @@ -1,12 +1,20 @@ @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 Maintenance Configuration to create.') param maintenanceConfigurationName 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 @@ -16,6 +24,18 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { kind: 'StorageV2' } +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, storageAccount.id, managedIdentity.id) + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b556d68e-0be0-4f35-a333-ad7ee1ce17ea' // Azure AI Enterprise Network Connection Approver + ) + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + resource maintenanceConfiguration 'Microsoft.Maintenance/maintenanceConfigurations@2023-10-01-preview' = { name: maintenanceConfigurationName location: location @@ -46,5 +66,8 @@ resource maintenanceConfiguration 'Microsoft.Maintenance/maintenanceConfiguratio @description('The resource ID of the created Storage Account.') output storageAccountResourceId string = storageAccount.id +@description('The name of the created Managed Identity.') +output managedIdentityName string = managedIdentity.name + @description('The resource ID of the maintenance configuration.') output maintenanceConfigurationResourceId string = maintenanceConfiguration.id diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep index 21d1ba8934..ec39ff7d58 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep @@ -44,6 +44,7 @@ module nestedDependencies 'dependencies.bicep' = { name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { storageAccountName: 'dep${namePrefix}st${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' maintenanceConfigurationName: 'dep-${namePrefix}-mc-${serviceShort}' location: enforcedLocation } @@ -60,6 +61,7 @@ module testDeployment '../../../main.bicep' = [ name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + managedIdentityName: nestedDependencies.outputs.managedIdentityName virtualMachineConfiguration: { adminUsername: 'localAdminUser' adminPassword: password diff --git a/avm/ptn/ai-platform/baseline/version.json b/avm/ptn/ai-platform/baseline/version.json index aa34c4d0f5..41fc8c654f 100644 --- a/avm/ptn/ai-platform/baseline/version.json +++ b/avm/ptn/ai-platform/baseline/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.4", + "version": "0.5", "pathFilters": [ "./main.json" ] From 432219fbad171fbb51886495b260820412ad0664 Mon Sep 17 00:00:00 2001 From: Ahmad Abdalla <28486158+ahmadabdalla@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:47:42 +1000 Subject: [PATCH 07/93] fix: Add explicit dependsOn in the privateLinkScope_privateEndpoints module for `avm/res/insights/private-link-scope` (#3348) ## Description Fixes #3208 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.insights.private-link-scope](https://github.com/ahmadabdalla/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml/badge.svg?branch=users%2Fahmad%2F3208_pls)](https://github.com/ahmadabdalla/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/insights/private-link-scope/README.md | 4 ++-- avm/res/insights/private-link-scope/main.bicep | 3 +++ avm/res/insights/private-link-scope/main.json | 13 +++++++------ .../private-link-scope/scoped-resource/main.json | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/avm/res/insights/private-link-scope/README.md b/avm/res/insights/private-link-scope/README.md index 4dda77b209..e8ef974f3c 100644 --- a/avm/res/insights/private-link-scope/README.md +++ b/avm/res/insights/private-link-scope/README.md @@ -770,7 +770,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope: | 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. | +| [`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. | @@ -788,7 +788,7 @@ Name of the private link scope. ### 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. +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 diff --git a/avm/res/insights/private-link-scope/main.bicep b/avm/res/insights/private-link-scope/main.bicep index 50534b0383..a6666eec33 100644 --- a/avm/res/insights/private-link-scope/main.bicep +++ b/avm/res/insights/private-link-scope/main.bicep @@ -203,6 +203,9 @@ module privateLinkScope_privateEndpoints 'br/public:avm/res/network/private-endp applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName } + dependsOn: [ + privateLinkScope_scopedResource + ] } ] diff --git a/avm/res/insights/private-link-scope/main.json b/avm/res/insights/private-link-scope/main.json index c1efbd235d..ecb92303a1 100644 --- a/avm/res/insights/private-link-scope/main.json +++ b/avm/res/insights/private-link-scope/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9210191494689145931" + "version": "0.30.3.12046", + "templateHash": "5947451992668490696" }, "name": "Azure Monitor Private Link Scopes", "description": "This module deploys an Azure Monitor Private Link Scope.", @@ -430,7 +430,7 @@ "accessModeSettings": { "$ref": "#/definitions/accessModeType", "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." + "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": { @@ -601,8 +601,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15704480901641345186" + "version": "0.30.3.12046", + "templateHash": "16277811786602972091" }, "name": "Private Link Scope Scoped Resources", "description": "This module deploys a Private Link Scope Scoped Resource.", @@ -1432,7 +1432,8 @@ } }, "dependsOn": [ - "privateLinkScope" + "privateLinkScope", + "privateLinkScope_scopedResource" ] } }, diff --git a/avm/res/insights/private-link-scope/scoped-resource/main.json b/avm/res/insights/private-link-scope/scoped-resource/main.json index 57e0b76f73..430361afb5 100644 --- a/avm/res/insights/private-link-scope/scoped-resource/main.json +++ b/avm/res/insights/private-link-scope/scoped-resource/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15704480901641345186" + "version": "0.30.3.12046", + "templateHash": "16277811786602972091" }, "name": "Private Link Scope Scoped Resources", "description": "This module deploys a Private Link Scope Scoped Resource.", From 33030a858a3cdbc466a1f4b4309b3725ea9743a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= Date: Tue, 24 Sep 2024 10:49:54 +0200 Subject: [PATCH 08/93] fix: `ptn/deployment-script/import-image-to-acr` overwriteExistingImage (#3350) ## Description Setting overwriteExistingImage to false, breaks the module as it will end with an error. Fixes #3349 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.deployment-script.import-image-to-acr](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml/badge.svg?branch=import-image-to-acr-fix)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [x] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/deployment-script/import-image-to-acr/main.bicep | 2 -- avm/ptn/deployment-script/import-image-to-acr/main.json | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/avm/ptn/deployment-script/import-image-to-acr/main.bicep b/avm/ptn/deployment-script/import-image-to-acr/main.bicep index 61534011ce..e6c532e567 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/main.bicep +++ b/avm/ptn/deployment-script/import-image-to-acr/main.bicep @@ -189,8 +189,6 @@ module imageImport 'br/public:avm/res/resources/deployment-script:0.4.0' = { containerGroupName: '${resourceGroup().name}-infrastructure' subnetResourceIds: subnetResourceIds scriptContent: '''#!/bin/bash - set -e - echo "Waiting on RBAC replication ($initialDelay)\n" sleep $initialDelay diff --git a/avm/ptn/deployment-script/import-image-to-acr/main.json b/avm/ptn/deployment-script/import-image-to-acr/main.json index 4f8a4504ae..6bfe24d5cd 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/main.json +++ b/avm/ptn/deployment-script/import-image-to-acr/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13166673091432959100" + "version": "0.30.3.12046", + "templateHash": "17375159703541878382" }, "name": "import-image-to-acr", "description": "This modules deployes an image to an Azure Container Registry.", @@ -368,7 +368,7 @@ "value": "[parameters('subnetResourceIds')]" }, "scriptContent": { - "value": "#!/bin/bash\n set -e\n\n echo \"Waiting on RBAC replication ($initialDelay)\\n\"\n sleep $initialDelay\n\n # retry loop to catch errors (usually RBAC delays, but 'Error copying blobs' is also not unheard of)\n retryLoopCount=0\n until [ $retryLoopCount -ge $retryMax ]\n do\n echo \"Importing Image ($retryLoopCount): $imageName into ACR: $acrName\\n\"\n if [ $overwriteExistingImage = 'true' ]; then\n if [ -n \"$sourceRegistryUsername\" ] && [ -n \"$sourceRegistryPassword\" ]; then\n az acr import -n $acrName --source $imageName --image $newImageName --force --username $sourceRegistryUsername --password $sourceRegistryPassword\n else\n az acr import -n $acrName --source $imageName --image $newImageName --force\n fi\n else\n if [ -n \"$sourceRegistryUsername\" ] && [ -n \"$sourceRegistryPassword\" ]; then\n az acr import -n $acrName --source $imageName --image $newImageName --username $sourceRegistryUsername --password $sourceRegistryPassword\n else\n az acr import -n $acrName --source $imageName --image $newImageName\n fi\n fi\n\n sleep $retrySleep\n retryLoopCount=$((retryLoopCount+1))\n done\n\n echo \"done\\n\"" + "value": "#!/bin/bash\n echo \"Waiting on RBAC replication ($initialDelay)\\n\"\n sleep $initialDelay\n\n # retry loop to catch errors (usually RBAC delays, but 'Error copying blobs' is also not unheard of)\n retryLoopCount=0\n until [ $retryLoopCount -ge $retryMax ]\n do\n echo \"Importing Image ($retryLoopCount): $imageName into ACR: $acrName\\n\"\n if [ $overwriteExistingImage = 'true' ]; then\n if [ -n \"$sourceRegistryUsername\" ] && [ -n \"$sourceRegistryPassword\" ]; then\n az acr import -n $acrName --source $imageName --image $newImageName --force --username $sourceRegistryUsername --password $sourceRegistryPassword\n else\n az acr import -n $acrName --source $imageName --image $newImageName --force\n fi\n else\n if [ -n \"$sourceRegistryUsername\" ] && [ -n \"$sourceRegistryPassword\" ]; then\n az acr import -n $acrName --source $imageName --image $newImageName --username $sourceRegistryUsername --password $sourceRegistryPassword\n else\n az acr import -n $acrName --source $imageName --image $newImageName\n fi\n fi\n\n sleep $retrySleep\n retryLoopCount=$((retryLoopCount+1))\n done\n\n echo \"done\\n\"" } }, "template": { From f08da65f2c6d3e53e8339b74bb33bfe8e20c361a Mon Sep 17 00:00:00 2001 From: Chinedum Echeta <60179183+cecheta@users.noreply.github.com> Date: Wed, 25 Sep 2024 01:56:19 -0700 Subject: [PATCH 09/93] feat: `avm/ptn/ai-platform/baseline` Use VNet AVM (#3353) ## Description This PR is essentially a revert of https://github.com/Azure/bicep-registry-modules/pull/3054, plus updating the version of the VNet module to the latest version. The VNet module now creates subnets as child modules, therefore we can use it instead of creating the resources ourselves. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.ai-platform.baseline](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml/badge.svg?branch=vnet-module)](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [x] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/ai-platform/baseline/README.md | 6 +- avm/ptn/ai-platform/baseline/main.bicep | 88 +- avm/ptn/ai-platform/baseline/main.json | 1706 +++++++++++++++++++-- avm/ptn/ai-platform/baseline/version.json | 2 +- 4 files changed, 1644 insertions(+), 158 deletions(-) diff --git a/avm/ptn/ai-platform/baseline/README.md b/avm/ptn/ai-platform/baseline/README.md index dfaf48f4a5..39a480afb9 100644 --- a/avm/ptn/ai-platform/baseline/README.md +++ b/avm/ptn/ai-platform/baseline/README.md @@ -51,13 +51,14 @@ By integrating with Microsoft Entra ID for secure identity management and utiliz | `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` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/virtualNetworkLinks) | -| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-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.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | | `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | | `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/virtualNetworkPeerings) | | `Microsoft.OperationalInsights/workspaces` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces) | | `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) | | `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts) | @@ -1150,6 +1151,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | `br/public:avm/res/network/bastion-host:0.2.2` | Remote reference | | `br/public:avm/res/network/network-security-group:0.3.1` | Remote reference | | `br/public:avm/res/network/private-dns-zone:0.3.1` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | | `br/public:avm/res/storage/storage-account:0.11.0` | Remote reference | ## Data Collection diff --git a/avm/ptn/ai-platform/baseline/main.bicep b/avm/ptn/ai-platform/baseline/main.bicep index 29b505f083..cfa8b0f7d7 100644 --- a/avm/ptn/ai-platform/baseline/main.bicep +++ b/avm/ptn/ai-platform/baseline/main.bicep @@ -59,7 +59,7 @@ var createVirtualMachine = createVirtualNetwork && virtualMachineConfiguration.? var createDefaultNsg = virtualNetworkConfiguration.?subnet.networkSecurityGroupResourceId == null -var subnetResourceId = createVirtualNetwork ? virtualNetwork::defaultSubnet.id : null +var subnetResourceId = createVirtualNetwork ? virtualNetwork.outputs.subnetResourceIds[0] : null var mlTargetSubResource = 'amlworkspace' @@ -103,7 +103,7 @@ module storageAccount_privateDnsZones 'br/public:avm/res/network/private-dns-zon name: zone virtualNetworkLinks: [ { - virtualNetworkResourceId: virtualNetwork.id + virtualNetworkResourceId: virtualNetwork.outputs.resourceId } ] } @@ -117,7 +117,7 @@ module workspaceHub_privateDnsZones 'br/public:avm/res/network/private-dns-zone: name: zone virtualNetworkLinks: [ { - virtualNetworkResourceId: virtualNetwork.id + virtualNetworkResourceId: virtualNetwork.outputs.resourceId } ] roleAssignments: managedIdentityName != null @@ -160,47 +160,37 @@ module defaultNetworkSecurityGroup 'br/public:avm/res/network/network-security-g } } -// Not using the br/public:avm/res/network/virtual-network module here to -// allow consumers of the module to add subnets from outside of the module -// https://github.com/Azure/bicep-registry-modules/issues/2689 -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = if (createVirtualNetwork) { - name: virtualNetworkConfiguration.?name ?? 'vnet-${name}' - location: location - tags: tags - properties: { - addressSpace: { - addressPrefixes: [ - virtualNetworkConfiguration.?addressPrefix ?? '10.0.0.0/16' - ] - } - } - - resource defaultSubnet 'subnets@2024-01-01' = { - name: virtualNetworkConfiguration.?subnet.name ?? 'default' - properties: { - addressPrefix: virtualNetworkConfiguration.?subnet.addressPrefix ?? '10.0.0.0/24' - networkSecurityGroup: { - id: createDefaultNsg - ? defaultNetworkSecurityGroup.outputs.resourceId - : virtualNetworkConfiguration.?subnet.networkSecurityGroupResourceId - } - } - } - - resource bastionSubnet 'subnets@2024-01-01' = if (createBastion) { - name: 'AzureBastionSubnet' - properties: { - addressPrefix: bastionConfiguration.?subnetAddressPrefix ?? '10.0.1.0/26' - networkSecurityGroup: bastionConfiguration.?networkSecurityGroupResourceId != null - ? { - id: bastionConfiguration.?networkSecurityGroupResourceId - } - : null - } - - dependsOn: [ - defaultSubnet +module virtualNetwork 'br/public:avm/res/network/virtual-network:0.4.0' = if (createVirtualNetwork) { + name: '${uniqueString(deployment().name, location)}-virtual-network' + params: { + name: virtualNetworkConfiguration.?name ?? 'vnet-${name}' + location: location + enableTelemetry: enableTelemetry + addressPrefixes: [ + virtualNetworkConfiguration.?addressPrefix ?? '10.0.0.0/16' ] + subnets: union( + // The default subnet **must** be the first in the subnets array + [ + { + addressPrefix: virtualNetworkConfiguration.?subnet.addressPrefix ?? '10.0.0.0/24' + name: virtualNetworkConfiguration.?subnet.name ?? 'default' + networkSecurityGroupResourceId: createDefaultNsg + ? defaultNetworkSecurityGroup.outputs.resourceId + : virtualNetworkConfiguration.?subnet.networkSecurityGroupResourceId + } + ], + createBastion + ? [ + { + addressPrefix: bastionConfiguration.?subnetAddressPrefix ?? '10.0.1.0/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: bastionConfiguration.?networkSecurityGroupResourceId + } + ] + : [] + ) + tags: tags } } @@ -211,7 +201,7 @@ module bastion 'br/public:avm/res/network/bastion-host:0.2.2' = if (createBastio location: location skuName: bastionConfiguration.?sku ?? 'Standard' enableTelemetry: enableTelemetry - virtualNetworkResourceId: virtualNetwork.id + virtualNetworkResourceId: virtualNetwork.outputs.resourceId disableCopyPaste: bastionConfiguration.?disableCopyPaste enableFileCopy: bastionConfiguration.?enableFileCopy enableIpConnect: bastionConfiguration.?enableIpConnect @@ -240,7 +230,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.5.3' = if (cr { name: virtualMachineConfiguration.?nicConfigurationConfiguration.ipConfigName ?? 'nic-vm-${name}-ipconfig' privateIPAllocationMethod: virtualMachineConfiguration.?nicConfigurationConfiguration.privateIPAllocationMethod ?? 'Dynamic' - subnetResourceId: virtualNetwork::defaultSubnet.id + subnetResourceId: virtualNetwork.outputs.subnetResourceIds[0] } ] } @@ -600,16 +590,16 @@ output workspaceProjectResourceId string = workspaceProject.outputs.resourceId output workspaceProjectName string = workspaceProject.outputs.name @description('The resource ID of the virtual network.') -output virtualNetworkResourceId string = createVirtualNetwork ? virtualNetwork.id : '' +output virtualNetworkResourceId string = createVirtualNetwork ? virtualNetwork.outputs.resourceId : '' @description('The name of the virtual network.') -output virtualNetworkName string = createVirtualNetwork ? virtualNetwork.name : '' +output virtualNetworkName string = createVirtualNetwork ? virtualNetwork.outputs.name : '' @description('The resource ID of the subnet in the virtual network.') -output virtualNetworkSubnetResourceId string = createVirtualNetwork ? virtualNetwork::defaultSubnet.id : '' +output virtualNetworkSubnetResourceId string = createVirtualNetwork ? virtualNetwork.outputs.subnetResourceIds[0] : '' @description('The name of the subnet in the virtual network.') -output virtualNetworkSubnetName string = createVirtualNetwork ? virtualNetwork::defaultSubnet.name : '' +output virtualNetworkSubnetName string = createVirtualNetwork ? virtualNetwork.outputs.subnetNames[0] : '' @description('The resource ID of the Azure Bastion host.') output bastionResourceId string = createBastion ? bastion.outputs.resourceId : '' diff --git a/avm/ptn/ai-platform/baseline/main.json b/avm/ptn/ai-platform/baseline/main.json index a6eafbcbbd..9da789cd5f 100644 --- a/avm/ptn/ai-platform/baseline/main.json +++ b/avm/ptn/ai-platform/baseline/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.3.12046", - "templateHash": "12442663604053803236" + "templateHash": "14736544493210620894" }, "name": "AI Platform Baseline", "description": "This module provides a secure and scalable environment for deploying AI applications on Azure.\nThe module encompasses all essential components required for building, managing, and observing AI solutions, including a machine learning workspace, observability tools, and necessary data management services.\nBy integrating with Microsoft Entra ID for secure identity management and utilizing private endpoints for services like Key Vault and Blob Storage, the module ensures secure communication and data access.", @@ -823,7 +823,6 @@ "createBastion": "[and(variables('createVirtualNetwork'), not(equals(tryGet(parameters('bastionConfiguration'), 'enabled'), false())))]", "createVirtualMachine": "[and(variables('createVirtualNetwork'), not(equals(tryGet(parameters('virtualMachineConfiguration'), 'enabled'), false())))]", "createDefaultNsg": "[equals(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'networkSecurityGroupResourceId'), null())]", - "subnetResourceId": "[if(variables('createVirtualNetwork'), resourceId('Microsoft.Network/virtualNetworks/subnets', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default')), null())]", "mlTargetSubResource": "amlworkspace", "mlPrivateDnsZones": { "privatelink.api.azureml.ms": "[variables('mlTargetSubResource')]", @@ -835,36 +834,6 @@ } }, "resources": { - "virtualNetwork::defaultSubnet": { - "condition": "[variables('createVirtualNetwork')]", - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'))]", - "properties": { - "addressPrefix": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'addressPrefix'), '10.0.0.0/24')]", - "networkSecurityGroup": { - "id": "[if(variables('createDefaultNsg'), reference('defaultNetworkSecurityGroup').outputs.resourceId.value, tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'networkSecurityGroupResourceId'))]" - } - }, - "dependsOn": [ - "defaultNetworkSecurityGroup", - "virtualNetwork" - ] - }, - "virtualNetwork::bastionSubnet": { - "condition": "[and(variables('createVirtualNetwork'), variables('createBastion'))]", - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), 'AzureBastionSubnet')]", - "properties": { - "addressPrefix": "[coalesce(tryGet(parameters('bastionConfiguration'), 'subnetAddressPrefix'), '10.0.1.0/26')]", - "networkSecurityGroup": "[if(not(equals(tryGet(parameters('bastionConfiguration'), 'networkSecurityGroupResourceId'), null())), createObject('id', tryGet(parameters('bastionConfiguration'), 'networkSecurityGroupResourceId')), null())]" - }, - "dependsOn": [ - "virtualNetwork::defaultSubnet", - "virtualNetwork" - ] - }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", @@ -885,21 +854,6 @@ } } }, - "virtualNetwork": { - "condition": "[variables('createVirtualNetwork')]", - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name')))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'addressPrefix'), '10.0.0.0/16')]" - ] - } - } - }, "userAssignedIdentity": { "condition": "[not(equals(parameters('managedIdentityName'), null()))]", "existing": true, @@ -949,7 +903,7 @@ "virtualNetworkLinks": { "value": [ { - "virtualNetworkResourceId": "[resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))))]" + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" } ] } @@ -3831,7 +3785,7 @@ "virtualNetworkLinks": { "value": [ { - "virtualNetworkResourceId": "[resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))))]" + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" } ] }, @@ -7235,61 +7189,1578 @@ "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" + ] + }, + "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(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/networkSecurityGroups', 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": [ + "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]" + } + } + } + } + }, + "virtualNetwork": { + "condition": "[variables('createVirtualNetwork')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtual-network', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name')))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "addressPrefixes": { + "value": [ + "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'addressPrefix'), '10.0.0.0/16')]" + ] + }, + "subnets": { + "value": "[union(createArray(createObject('addressPrefix', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'addressPrefix'), '10.0.0.0/24'), 'name', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'), 'networkSecurityGroupResourceId', if(variables('createDefaultNsg'), reference('defaultNetworkSecurityGroup').outputs.resourceId.value, tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'networkSecurityGroupResourceId')))), if(variables('createBastion'), createArray(createObject('addressPrefix', coalesce(tryGet(parameters('bastionConfiguration'), 'subnetAddressPrefix'), '10.0.1.0/26'), 'name', 'AzureBastionSubnet', 'networkSecurityGroupResourceId', tryGet(parameters('bastionConfiguration'), 'networkSecurityGroupResourceId'))), 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.29.47.4906", + "templateHash": "15949466154563447171" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "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 + }, + "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 + }, + "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" + ], + "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": { + "$ref": "#/definitions/roleAssignmentType", + "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." + } + } + } + } + }, + "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": { + "$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." + } + }, + "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('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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "5699372618313647761" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "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 + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Requird. 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", + "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", + "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": { + "$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')]", + "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": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "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" ] }, - "networkSecurityGroup_diagnosticSettings": { + "virtualNetwork_peering_local": { "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), 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')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "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())]" + "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.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "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'))]" } } - ], - "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" + "virtualNetwork" ] }, - "networkSecurityGroup_roleAssignments": { + "virtualNetwork_peering_remote": { "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": { - "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')]" + "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.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "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": [ - "networkSecurityGroup" + "virtualNetwork" ] } }, @@ -7297,34 +8768,57 @@ "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the network security group was deployed into." + "description": "The resource group the virtual network was deployed into." }, "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the network security group." + "description": "The resource ID of the virtual network." }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" }, "name": { "type": "string", "metadata": { - "description": "The name of the network security group." + "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('networkSecurityGroup', '2023-11-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" } } } - } + }, + "dependsOn": [ + "defaultNetworkSecurityGroup" + ] }, "bastion": { "condition": "[variables('createBastion')]", @@ -7350,7 +8844,7 @@ "value": "[parameters('enableTelemetry')]" }, "virtualNetworkResourceId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))))]" + "value": "[reference('virtualNetwork').outputs.resourceId.value]" }, "disableCopyPaste": { "value": "[tryGet(parameters('bastionConfiguration'), 'disableCopyPaste')]" @@ -8549,7 +10043,7 @@ { "name": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'nicConfigurationConfiguration', 'ipConfigName'), format('nic-vm-{0}-ipconfig', parameters('name')))]", "privateIPAllocationMethod": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'nicConfigurationConfiguration', 'privateIPAllocationMethod'), 'Dynamic')]", - "subnetResourceId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'))]" + "subnetResourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[0]]" } ] } @@ -13968,7 +15462,7 @@ } }, "dependsOn": [ - "virtualNetwork::defaultSubnet" + "virtualNetwork" ] }, "keyVault": { @@ -16805,7 +18299,7 @@ "bypass": "AzureServices" } }, - "privateEndpoints": "[if(not(equals(variables('subnetResourceId'), null())), createObject('value', map(items(variables('storagePrivateDnsZones')), lambda('zone', createObject('name', format('pep-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'service', lambdaVariables('zone').value, 'subnetResourceId', coalesce(variables('subnetResourceId'), ''), 'privateDnsZoneResourceIds', createArray(resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone').key)))))), createObject('value', null()))]", + "privateEndpoints": "[if(not(equals(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), null())), createObject('value', map(items(variables('storagePrivateDnsZones')), lambda('zone', createObject('name', format('pep-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'service', lambdaVariables('zone').value, 'subnetResourceId', coalesce(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), ''), 'privateDnsZoneResourceIds', createArray(resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone').key)))))), createObject('value', null()))]", "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Storage Blob Data Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', '69566ab7-960f-475b-8e7c-b3118f30c6bd', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" @@ -21469,9 +22963,9 @@ } }, "dependsOn": [ - "virtualNetwork::defaultSubnet", "storageAccount_privateDnsZones", - "userAssignedIdentity" + "userAssignedIdentity", + "virtualNetwork" ] }, "containerRegistry": { @@ -24315,7 +25809,7 @@ "outboundRules": "[tryGet(parameters('workspaceConfiguration'), 'networkOutboundRules')]" } }, - "privateEndpoints": "[if(not(equals(variables('subnetResourceId'), null())), createObject('value', createArray(createObject('name', format('pep-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'service', variables('mlTargetSubResource'), 'subnetResourceId', coalesce(variables('subnetResourceId'), ''), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', map(objectKeys(variables('mlPrivateDnsZones')), lambda('zone', createObject('name', replace(lambdaVariables('zone'), '.', '-'), 'privateDnsZoneResourceId', resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone'))))))))), createObject('value', null()))]", + "privateEndpoints": "[if(not(equals(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), null())), createObject('value', createArray(createObject('name', format('pep-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'service', variables('mlTargetSubResource'), 'subnetResourceId', coalesce(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), ''), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', map(objectKeys(variables('mlPrivateDnsZones')), lambda('zone', createObject('name', replace(lambdaVariables('zone'), '.', '-'), 'privateDnsZoneResourceId', resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone'))))))))), createObject('value', null()))]", "systemDatastoresAuthMode": { "value": "identity" }, @@ -26563,10 +28057,10 @@ "dependsOn": [ "applicationInsights", "containerRegistry", - "virtualNetwork::defaultSubnet", "keyVault", "storageAccount", "userAssignedIdentity", + "virtualNetwork", "workspaceHub_privateDnsZones" ] }, @@ -29005,28 +30499,28 @@ "metadata": { "description": "The resource ID of the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name')))), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.resourceId.value, '')]" }, "virtualNetworkName": { "type": "string", "metadata": { "description": "The name of the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.name.value, '')]" }, "virtualNetworkSubnetResourceId": { "type": "string", "metadata": { "description": "The resource ID of the subnet in the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), resourceId('Microsoft.Network/virtualNetworks/subnets', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default')), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], '')]" }, "virtualNetworkSubnetName": { "type": "string", "metadata": { "description": "The name of the subnet in the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetNames.value[0], '')]" }, "bastionResourceId": { "type": "string", diff --git a/avm/ptn/ai-platform/baseline/version.json b/avm/ptn/ai-platform/baseline/version.json index 41fc8c654f..c332ff1f3a 100644 --- a/avm/ptn/ai-platform/baseline/version.json +++ b/avm/ptn/ai-platform/baseline/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.5", + "version": "0.6", "pathFilters": [ "./main.json" ] From 51596f2d87a24e51f0ef8bf37e7b8f2af5d23d79 Mon Sep 17 00:00:00 2001 From: Chinedum Echeta <60179183+cecheta@users.noreply.github.com> Date: Wed, 25 Sep 2024 02:40:38 -0700 Subject: [PATCH 10/93] docs: `avm/ptn/ai-platform/baseline` Update README (#3358) ## Description Updating the README, which changed since the last PR was raised ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.ai-platform.baseline](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml/badge.svg?branch=readme)](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/ai-platform/baseline/README.md | 12 ++++++------ avm/ptn/ai-platform/baseline/main.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/avm/ptn/ai-platform/baseline/README.md b/avm/ptn/ai-platform/baseline/README.md index 39a480afb9..709ebd90fe 100644 --- a/avm/ptn/ai-platform/baseline/README.md +++ b/avm/ptn/ai-platform/baseline/README.md @@ -65,14 +65,14 @@ By integrating with Microsoft Entra ID for secure identity management and utiliz | `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/storageAccounts/fileServices) | +| `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/storageAccounts/localUsers) | +| `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/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `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 diff --git a/avm/ptn/ai-platform/baseline/main.json b/avm/ptn/ai-platform/baseline/main.json index 9da789cd5f..cbb20a89d4 100644 --- a/avm/ptn/ai-platform/baseline/main.json +++ b/avm/ptn/ai-platform/baseline/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.3.12046", - "templateHash": "14736544493210620894" + "version": "0.30.23.60470", + "templateHash": "14190804454906731332" }, "name": "AI Platform Baseline", "description": "This module provides a secure and scalable environment for deploying AI applications on Azure.\nThe module encompasses all essential components required for building, managing, and observing AI solutions, including a machine learning workspace, observability tools, and necessary data management services.\nBy integrating with Microsoft Entra ID for secure identity management and utilizing private endpoints for services like Key Vault and Blob Storage, the module ensures secure communication and data access.", From d213e8a8a0149f9ad72cfb037b0917af552d6af1 Mon Sep 17 00:00:00 2001 From: Nate Arnold Date: Wed, 25 Sep 2024 05:57:42 -0600 Subject: [PATCH 11/93] fix: Added depends_on to flexibleserver_administrators (#3355) ## Description Fixes #3257 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.db-for-postgre-sql.flexible-server](https://github.com/arnoldna/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=avm%2Fres%2Fdb-for-postgre-sql%2Fflexible-server2)](https://github.com/arnoldna/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml) | ## Type of Change - [X] Update to CI Environment or utilities (Non-module affecting changes) - [X] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/db-for-postgre-sql/flexible-server/main.bicep | 3 +++ avm/res/db-for-postgre-sql/flexible-server/main.json | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/main.bicep index 19c07e2e2f..7b24eb2bc7 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/main.bicep @@ -377,6 +377,9 @@ module flexibleServer_administrators 'administrator/main.bicep' = [ principalType: administrator.principalType tenantId: administrator.?tenantId ?? tenant().tenantId } + dependsOn: [ + flexibleServer_configurations + ] } ] diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.json b/avm/res/db-for-postgre-sql/flexible-server/main.json index 9472f5d8f9..3e71af1f04 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.json +++ b/avm/res/db-for-postgre-sql/flexible-server/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "745168326315156090" + "templateHash": "16193893481581771669" }, "name": "DBforPostgreSQL Flexible Servers", "description": "This module deploys a DBforPostgreSQL Flexible Server.", @@ -1193,7 +1193,8 @@ } }, "dependsOn": [ - "flexibleServer" + "flexibleServer", + "flexibleServer_configurations" ] } }, From 5fc18d3c5929f8cb031b371bf6974d55b1e803c0 Mon Sep 17 00:00:00 2001 From: hundredacres Date: Wed, 25 Sep 2024 09:06:49 -0700 Subject: [PATCH 12/93] fix: Resolve issue when bastion/firewall is not deployed (#3356) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Resolves issue when bastion and firewall are not deployed. Added test to confirm. Fixes #3343 Closes #3343 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.network.hub-networking](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.ptn.network.hub-networking.yml/badge.svg?branch=fix%2Fissues%2F3343)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.ptn.network.hub-networking.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [X] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/ptn/network/hub-networking/README.md | 173 +++++++++++++++++- avm/ptn/network/hub-networking/main.bicep | 28 +-- avm/ptn/network/hub-networking/main.json | 30 +-- .../tests/e2e/no-addons/main.test.bicep | 124 +++++++++++++ 4 files changed, 321 insertions(+), 34 deletions(-) create mode 100644 avm/ptn/network/hub-networking/tests/e2e/no-addons/main.test.bicep diff --git a/avm/ptn/network/hub-networking/README.md b/avm/ptn/network/hub-networking/README.md index 9dd17dbb8d..e033907b82 100644 --- a/avm/ptn/network/hub-networking/README.md +++ b/avm/ptn/network/hub-networking/README.md @@ -38,7 +38,8 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using large parameter set](#example-2-using-large-parameter-set) -- [WAF-aligned](#example-3-waf-aligned) +- [No Addons](#example-3-no-addons) +- [WAF-aligned](#example-4-waf-aligned) ### Example 1: _Using only defaults_ @@ -448,7 +449,175 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

-### Example 3: _WAF-aligned_ +### Example 3: _No Addons_ + +This instance deploys the module with no add-ons (Firewall / Bastion) enabled. + + +

+ +via Bicep module + +```bicep +module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = { + name: 'hubNetworkingDeployment' + params: { + hubVirtualNetworks: { + hub1: { + addressPrefixes: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.6' + '10.0.1.7' + ] + enableAzureFirewall: false + enableBastion: false + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + location: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "hubVirtualNetworks": { + "value": { + "hub1": { + "addressPrefixes": "", + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "dnsServers": [ + "10.0.1.6", + "10.0.1.7" + ], + "enableAzureFirewall": false, + "enableBastion": false, + "enablePeering": false, + "enableTelemetry": true, + "flowTimeoutInMinutes": 30, + "location": "", + "lock": { + "kind": "CanNotDelete", + "name": "hub1Lock" + }, + "routes": [ + { + "name": "defaultRoute", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopType": "Internet" + } + } + ], + "subnets": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "vnetEncryption": false, + "vnetEncryptionEnforcement": "AllowUnencrypted" + } + } + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. diff --git a/avm/ptn/network/hub-networking/main.bicep b/avm/ptn/network/hub-networking/main.bicep index 981cdd4eff..2f222c6bc0 100644 --- a/avm/ptn/network/hub-networking/main.bicep +++ b/avm/ptn/network/hub-networking/main.bicep @@ -245,22 +245,26 @@ output hubVirtualNetworks object[] = [ @description('Array of hub bastion resources.') output hubBastions object[] = [ - for (hub, index) in items(hubVirtualNetworks ?? {}): { - resourceGroupName: hubBastion[index].outputs.resourceGroupName - location: hubBastion[index].outputs.location - name: hubBastion[index].outputs.name - resourceId: hubBastion[index].outputs.resourceId - } + for (hub, index) in items(hubVirtualNetworks ?? {}): (hub.value.enableBastion) + ? { + resourceGroupName: hubBastion[index].outputs.resourceGroupName + location: hubBastion[index].outputs.location + name: hubBastion[index].outputs.name + resourceId: hubBastion[index].outputs.resourceId + } + : {} ] @description('Array of hub Azure Firewall resources.') output hubAzureFirewalls object[] = [ - for (hub, index) in items(hubVirtualNetworks ?? {}): { - resourceGroupName: hubAzureFirewall[index].outputs.resourceGroupName - location: hubAzureFirewall[index].outputs.location - name: hubAzureFirewall[index].outputs.name - resourceId: hubAzureFirewall[index].outputs.resourceId - } + for (hub, index) in items(hubVirtualNetworks ?? {}): (hub.value.enableAzureFirewall) + ? { + resourceGroupName: hubAzureFirewall[index].outputs.resourceGroupName + location: hubAzureFirewall[index].outputs.location + name: hubAzureFirewall[index].outputs.name + resourceId: hubAzureFirewall[index].outputs.resourceId + } + : {} ] @description('The subnets of the hub virtual network.') diff --git a/avm/ptn/network/hub-networking/main.json b/avm/ptn/network/hub-networking/main.json index 8fb5cb887b..6cac966757 100644 --- a/avm/ptn/network/hub-networking/main.json +++ b/avm/ptn/network/hub-networking/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9188161100861636713" + "version": "0.30.3.12046", + "templateHash": "8969613921663763778" }, "name": "Hub Networking", "description": "This module is designed to simplify the creation of multi-region hub networks in Azure. It will create a number of virtual networks and subnets, and optionally peer them together in a mesh topology with routing.", @@ -2315,8 +2315,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15958982442955537466" + "version": "0.30.3.12046", + "templateHash": "5568850224456572684" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network.", @@ -6436,8 +6436,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13190798974838698070" + "version": "0.30.3.12046", + "templateHash": "16563975082451649304" }, "name": "Existing Virtual Network Subnets", "description": "This module retrieves an existing Virtual Network Subnet.", @@ -6519,8 +6519,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11735652948112662202" + "version": "0.30.3.12046", + "templateHash": "10294962787410461549" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -6859,12 +6859,7 @@ }, "copy": { "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", - "input": { - "resourceGroupName": "[reference(format('hubBastion[{0}]', copyIndex())).outputs.resourceGroupName.value]", - "location": "[reference(format('hubBastion[{0}]', copyIndex())).outputs.location.value]", - "name": "[reference(format('hubBastion[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('hubBastion[{0}]', copyIndex())).outputs.resourceId.value]" - } + "input": "[if(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableBastion, createObject('resourceGroupName', reference(format('hubBastion[{0}]', copyIndex())).outputs.resourceGroupName.value, 'location', reference(format('hubBastion[{0}]', copyIndex())).outputs.location.value, 'name', reference(format('hubBastion[{0}]', copyIndex())).outputs.name.value, 'resourceId', reference(format('hubBastion[{0}]', copyIndex())).outputs.resourceId.value), createObject())]" } }, "hubAzureFirewalls": { @@ -6877,12 +6872,7 @@ }, "copy": { "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", - "input": { - "resourceGroupName": "[reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.resourceGroupName.value]", - "location": "[reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.location.value]", - "name": "[reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.resourceId.value]" - } + "input": "[if(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableAzureFirewall, createObject('resourceGroupName', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.resourceGroupName.value, 'location', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.location.value, 'name', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.name.value, 'resourceId', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.resourceId.value), createObject())]" } }, "hubVirtualNetworkSubnets": { diff --git a/avm/ptn/network/hub-networking/tests/e2e/no-addons/main.test.bicep b/avm/ptn/network/hub-networking/tests/e2e/no-addons/main.test.bicep new file mode 100644 index 0000000000..12d7a9613a --- /dev/null +++ b/avm/ptn/network/hub-networking/tests/e2e/no-addons/main.test.bicep @@ -0,0 +1,124 @@ +targetScope = 'subscription' + +metadata name = 'No Addons' +metadata description = 'This instance deploys the module with no add-ons (Firewall / Bastion) enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.hub-networking-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nhnnadd' + +@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 +} + +// 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: { + // You parameters go here + location: resourceLocation + hubVirtualNetworks: { + hub1: { + addressPrefixes: array(addressPrefix) + enableAzureFirewall: false + enableBastion: false + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + dnsServers: ['10.0.1.6', '10.0.1.7'] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + name: 'GatewaySubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + { + name: 'AzureFirewallSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + { + name: 'AzureBastionSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 2) + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + } + } +] From 57769c252159f9c25c12e67bc33938f6790236c8 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 26 Sep 2024 03:08:22 +0200 Subject: [PATCH 13/93] fix: StorageAccount - Added implicit dependency to blobServices from container (#3254) ## Description - Added implicit dependency to blobServices from container Closes #3210 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.storage.storage-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=users%2Falsehr%2FsaDep&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- .../blob-service/container/README.md | 9 +++++++ .../blob-service/container/main.bicep | 5 +++- .../blob-service/container/main.json | 19 ++++++++----- .../storage-account/blob-service/main.bicep | 1 + .../storage-account/blob-service/main.json | 25 ++++++++++++----- avm/res/storage/storage-account/main.json | 27 +++++++++++++------ 6 files changed, 64 insertions(+), 22 deletions(-) diff --git a/avm/res/storage/storage-account/blob-service/container/README.md b/avm/res/storage/storage-account/blob-service/container/README.md index c66f943899..34d861e3b5 100644 --- a/avm/res/storage/storage-account/blob-service/container/README.md +++ b/avm/res/storage/storage-account/blob-service/container/README.md @@ -34,6 +34,7 @@ This module deploys a Storage Account Blob Container. | 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. | @@ -59,6 +60,14 @@ The name of the parent Storage Account. Required if the template is used in a st - 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. diff --git a/avm/res/storage/storage-account/blob-service/container/main.bicep b/avm/res/storage/storage-account/blob-service/container/main.bicep index fa0193da72..9a19a6096f 100644 --- a/avm/res/storage/storage-account/blob-service/container/main.bicep +++ b/avm/res/storage/storage-account/blob-service/container/main.bicep @@ -6,6 +6,9 @@ metadata owner = 'Azure/module-maintainers' @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 @@ -105,7 +108,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing name: storageAccountName resource blobServices 'blobServices@2022-09-01' existing = { - name: 'default' + name: blobServiceName } } diff --git a/avm/res/storage/storage-account/blob-service/container/main.json b/avm/res/storage/storage-account/blob-service/container/main.json index 98d00e679f..92a5cbbbd0 100644 --- a/avm/res/storage/storage-account/blob-service/container/main.json +++ b/avm/res/storage/storage-account/blob-service/container/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1020003258393866601" + "templateHash": "3558916747425087131" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -95,6 +95,13 @@ "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": { @@ -205,7 +212,7 @@ "existing": true, "type": "Microsoft.Storage/storageAccounts/blobServices", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]", "dependsOn": [ "storageAccount" ] @@ -219,7 +226,7 @@ "container": { "type": "Microsoft.Storage/storageAccounts/blobServices/containers", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", "properties": { "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", @@ -240,8 +247,8 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "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]", @@ -387,7 +394,7 @@ "metadata": { "description": "The resource ID of the deployed container." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", diff --git a/avm/res/storage/storage-account/blob-service/main.bicep b/avm/res/storage/storage-account/blob-service/main.bicep index c02c02f6fa..bb43c4d610 100644 --- a/avm/res/storage/storage-account/blob-service/main.bicep +++ b/avm/res/storage/storage-account/blob-service/main.bicep @@ -149,6 +149,7 @@ module blobServices_container 'container/main.bicep' = [ name: '${deployment().name}-Container-${index}' params: { storageAccountName: storageAccount.name + blobServiceName: blobServices.name name: container.name defaultEncryptionScope: container.?defaultEncryptionScope denyEncryptionScopeOverride: container.?denyEncryptionScopeOverride diff --git a/avm/res/storage/storage-account/blob-service/main.json b/avm/res/storage/storage-account/blob-service/main.json index 7531267468..944846b041 100644 --- a/avm/res/storage/storage-account/blob-service/main.json +++ b/avm/res/storage/storage-account/blob-service/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17077763197163073998" + "templateHash": "16657059190807174649" }, "name": "Storage Account blob Services", "description": "This module deploys a Storage Account Blob Service.", @@ -365,6 +365,9 @@ "storageAccountName": { "value": "[parameters('storageAccountName')]" }, + "blobServiceName": { + "value": "[variables('name')]" + }, "name": { "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" }, @@ -404,7 +407,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1020003258393866601" + "templateHash": "3558916747425087131" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -493,6 +496,13 @@ "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": { @@ -603,7 +613,7 @@ "existing": true, "type": "Microsoft.Storage/storageAccounts/blobServices", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]", "dependsOn": [ "storageAccount" ] @@ -617,7 +627,7 @@ "container": { "type": "Microsoft.Storage/storageAccounts/blobServices/containers", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", "properties": { "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", @@ -638,8 +648,8 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "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]", @@ -785,7 +795,7 @@ "metadata": { "description": "The resource ID of the deployed container." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", @@ -798,6 +808,7 @@ } }, "dependsOn": [ + "blobServices", "storageAccount" ] } diff --git a/avm/res/storage/storage-account/main.json b/avm/res/storage/storage-account/main.json index 38e3f3d998..8120b7936e 100644 --- a/avm/res/storage/storage-account/main.json +++ b/avm/res/storage/storage-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "6735651687082765200" + "templateHash": "8986504733456130232" }, "name": "Storage Accounts", "description": "This module deploys a Storage Account.", @@ -2266,7 +2266,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17077763197163073998" + "templateHash": "16657059190807174649" }, "name": "Storage Account blob Services", "description": "This module deploys a Storage Account Blob Service.", @@ -2625,6 +2625,9 @@ "storageAccountName": { "value": "[parameters('storageAccountName')]" }, + "blobServiceName": { + "value": "[variables('name')]" + }, "name": { "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" }, @@ -2664,7 +2667,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1020003258393866601" + "templateHash": "3558916747425087131" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -2753,6 +2756,13 @@ "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": { @@ -2863,7 +2873,7 @@ "existing": true, "type": "Microsoft.Storage/storageAccounts/blobServices", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]", "dependsOn": [ "storageAccount" ] @@ -2877,7 +2887,7 @@ "container": { "type": "Microsoft.Storage/storageAccounts/blobServices/containers", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", "properties": { "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", @@ -2898,8 +2908,8 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "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]", @@ -3045,7 +3055,7 @@ "metadata": { "description": "The resource ID of the deployed container." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", @@ -3058,6 +3068,7 @@ } }, "dependsOn": [ + "blobServices", "storageAccount" ] } From 717e7fd82c698a28e2d152c2b1c39ddee6fe48ac Mon Sep 17 00:00:00 2001 From: Buddy <38195643+tsc-buddy@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:00:53 +1200 Subject: [PATCH 14/93] fix: test updates for az defaults (#3344) ## Description Addressing the AZ defaults now that the PSRule test bug has been addressed [here](https://github.com/microsoft/PSRule/issues/1900#issuecomment-2356575578). ## Pipeline Reference | Pipeline | | -------- | |[![avm.res.web.serverfarm](https://github.com/tsc-buddy/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=fix%2Fasp-zr-default)](https://github.com/tsc-buddy/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml)| ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [x] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/web/serverfarm/README.md | 96 +++++++++---------- avm/res/web/serverfarm/main.bicep | 19 ++-- avm/res/web/serverfarm/main.json | 12 ++- .../tests/e2e/defaults/main.test.bicep | 4 +- .../serverfarm/tests/e2e/max/main.test.bicep | 8 +- .../tests/e2e/waf-aligned/main.test.bicep | 6 +- 6 files changed, 70 insertions(+), 75 deletions(-) diff --git a/avm/res/web/serverfarm/README.md b/avm/res/web/serverfarm/README.md index 0df60a5510..152351ffe2 100644 --- a/avm/res/web/serverfarm/README.md +++ b/avm/res/web/serverfarm/README.md @@ -46,8 +46,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { params: { // Required parameters name: 'wsfmin001' - skuCapacity: 2 - skuName: 'S1' // Non-required parameters location: '' } @@ -70,12 +68,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": { "value": "wsfmin001" }, - "skuCapacity": { - "value": 2 - }, - "skuName": { - "value": "S1" - }, // Non-required parameters "location": { "value": "" @@ -102,8 +94,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { params: { // Required parameters name: 'wsfmax001' - skuCapacity: 1 - skuName: 'S1' // Non-required parameters diagnosticSettings: [ { @@ -143,12 +133,14 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { roleDefinitionIdOrName: '' } ] + skuCapacity: 3 + skuName: 'P1v3' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - zoneRedundant: false + zoneRedundant: true } } ``` @@ -169,12 +161,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": { "value": "wsfmax001" }, - "skuCapacity": { - "value": 1 - }, - "skuName": { - "value": "S1" - }, // Non-required parameters "diagnosticSettings": { "value": [ @@ -226,6 +212,12 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { } ] }, + "skuCapacity": { + "value": 3 + }, + "skuName": { + "value": "P1v3" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -234,7 +226,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { } }, "zoneRedundant": { - "value": false + "value": true } } } @@ -258,8 +250,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { params: { // Required parameters name: 'wsfwaf001' - skuCapacity: 2 - skuName: 'P1v3' // Non-required parameters diagnosticSettings: [ { @@ -281,12 +271,14 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { kind: 'CanNotDelete' name: 'lock' } + skuCapacity: 3 + skuName: 'P1v3' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - zoneRedundant: false + zoneRedundant: true } } ``` @@ -307,12 +299,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": { "value": "wsfwaf001" }, - "skuCapacity": { - "value": 2 - }, - "skuName": { - "value": "P1v3" - }, // Non-required parameters "diagnosticSettings": { "value": [ @@ -342,6 +328,12 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": "lock" } }, + "skuCapacity": { + "value": 3 + }, + "skuName": { + "value": "P1v3" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -350,7 +342,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { } }, "zoneRedundant": { - "value": false + "value": true } } } @@ -366,8 +358,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { | Parameter | Type | Description | | :-- | :-- | :-- | | [`name`](#parameter-name) | string | Name of the app service plan. | -| [`skuCapacity`](#parameter-skucapacity) | int | Number of workers associated with the App Service Plan. | -| [`skuName`](#parameter-skuname) | string | The name of the SKU will Determine the tier, size, family of the App Service Plan. | **Conditional parameters** @@ -389,6 +379,8 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { | [`maximumElasticWorkerCount`](#parameter-maximumelasticworkercount) | int | Maximum number of total workers allowed for this ElasticScaleEnabled App Service Plan. | | [`perSiteScaling`](#parameter-persitescaling) | bool | If true, apps assigned to this App Service plan can be scaled independently. If false, apps assigned to this App Service plan will scale to all instances of the plan. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`skuCapacity`](#parameter-skucapacity) | int | Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones. | +| [`skuName`](#parameter-skuname) | string | The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`targetWorkerCount`](#parameter-targetworkercount) | int | Scaling worker count. | | [`targetWorkerSize`](#parameter-targetworkersize) | int | The instance size of the hosting plan (small, medium, or large). | @@ -402,27 +394,6 @@ Name of the app service plan. - Required: Yes - Type: string -### Parameter: `skuCapacity` - -Number of workers associated with the App Service Plan. - -- Required: Yes -- Type: int - -### Parameter: `skuName` - -The name of the SKU will Determine the tier, size, family of the App Service Plan. - -- Required: Yes -- Type: string -- Example: - ```Bicep - 'F1' - 'B1' - 'P1v3' - 'I1v2' - ``` - ### Parameter: `reserved` Defaults to false when creating Windows/app App Service Plan. Required if creating a Linux App Service Plan and must be set to true. @@ -739,6 +710,29 @@ The principal type of the assigned principal ID. ] ``` +### Parameter: `skuCapacity` + +Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones. + +- Required: No +- Type: int +- Default: `3` + +### Parameter: `skuName` + +The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones. + +- Required: No +- Type: string +- Default: `'P1v3'` +- Example: + ```Bicep + 'F1' + 'B1' + 'P1v3' + 'I1v2' + ``` + ### Parameter: `tags` Tags of the resource. diff --git a/avm/res/web/serverfarm/main.bicep b/avm/res/web/serverfarm/main.bicep index cd823f28ce..a9dc015538 100644 --- a/avm/res/web/serverfarm/main.bicep +++ b/avm/res/web/serverfarm/main.bicep @@ -7,7 +7,7 @@ metadata owner = 'Azure/module-maintainers' @maxLength(60) param name string -@description('Required. The name of the SKU will Determine the tier, size, family of the App Service Plan.') +@description('Optional. The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones.') @metadata({ example: ''' 'F1' @@ -16,10 +16,10 @@ param name string 'I1v2' ''' }) -param skuName string +param skuName string = 'P1v3' -@description('Required. Number of workers associated with the App Service Plan.') -param skuCapacity int +@description('Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones.') +param skuCapacity int = 3 @description('Optional. Location for all resources.') param location string = resourceGroup().location @@ -185,11 +185,12 @@ resource appServicePlan_roleAssignments 'Microsoft.Authorization/roleAssignments for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(appServicePlan.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) properties: { - roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) - ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] - : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') - ? roleAssignment.roleDefinitionIdOrName - : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType diff --git a/avm/res/web/serverfarm/main.json b/avm/res/web/serverfarm/main.json index 68729b8033..ba4108ee0b 100644 --- a/avm/res/web/serverfarm/main.json +++ b/avm/res/web/serverfarm/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16609348340052214807" + "version": "0.30.3.12046", + "templateHash": "12599229174633311842" }, "name": "App Service Plan", "description": "This module deploys an App Service Plan.", @@ -203,15 +203,17 @@ }, "skuName": { "type": "string", + "defaultValue": "P1v3", "metadata": { "example": " 'F1'\n 'B1'\n 'P1v3'\n 'I1v2'\n ", - "description": "Required. The name of the SKU will Determine the tier, size, family of the App Service Plan." + "description": "Optional. The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones." } }, "skuCapacity": { "type": "int", + "defaultValue": 3, "metadata": { - "description": "Required. Number of workers associated with the App Service Plan." + "description": "Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones." } }, "location": { @@ -447,7 +449,7 @@ "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Web/serverfarms', 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)))]", + "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')]", diff --git a/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep index 1de03468ef..afb9a3ac26 100644 --- a/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep @@ -18,7 +18,7 @@ param serviceShort string = 'wsfmin' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var enforcedLocation = 'eastus' +var enforcedLocation = 'australiaeast' // ============ // // Dependencies // @@ -43,8 +43,6 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: enforcedLocation - skuName: 'S1' - skuCapacity: 2 } } ] diff --git a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep index b5d2046b5f..7b0bd49b7c 100644 --- a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep @@ -18,7 +18,7 @@ param serviceShort string = 'wsfmax' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var enforcedLocation = 'eastus' +var enforcedLocation = 'australiaeast' // ============ // // Dependencies // @@ -64,10 +64,10 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: enforcedLocation - skuName: 'S1' - skuCapacity: 1 + skuName: 'P1v3' + skuCapacity: 3 perSiteScaling: true - zoneRedundant: false + zoneRedundant: true kind: 'App' lock: { name: 'lock' diff --git a/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep index 15eb7e25be..3e0e62dd53 100644 --- a/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep @@ -18,7 +18,7 @@ param serviceShort string = 'wsfwaf' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var enforcedLocation = 'eastus' +var enforcedLocation = 'australiaeast' // ============ // // Dependencies // @@ -56,8 +56,8 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: enforcedLocation skuName: 'P1v3' - skuCapacity: 2 - zoneRedundant: false + skuCapacity: 3 + zoneRedundant: true kind: 'App' lock: { name: 'lock' From 032457048e32f131aa9578da896bc0b801ecd0e5 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 26 Sep 2024 11:37:22 +0200 Subject: [PATCH 15/93] fix: Added a fixed uksouth location for `avm.res.dev-ops-infrastructure.pool` (#3351) ## Description This pull request introduces a fixed location (uksouth) used to run the validation deployments. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.dev-ops-infrastructure.pool](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml/badge.svg?branch=johnlokerse%2Fenforce-location-mdp)](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml) | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/dev-ops-infrastructure/pool/main.json | 4 ++-- .../pool/tests/e2e/defaults/main.test.bicep | 17 +++++++++-------- .../pool/tests/e2e/max/main.test.bicep | 17 +++++++++-------- .../pool/tests/e2e/waf-aligned/main.test.bicep | 17 +++++++++-------- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/avm/res/dev-ops-infrastructure/pool/main.json b/avm/res/dev-ops-infrastructure/pool/main.json index ce80f4d180..689ef6eb8c 100644 --- a/avm/res/dev-ops-infrastructure/pool/main.json +++ b/avm/res/dev-ops-infrastructure/pool/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.3.12046", - "templateHash": "15191897376801297199" + "version": "0.30.23.60470", + "templateHash": "3502193398932835678" }, "name": "Managed DevOps Pool", "description": "This module deploys the Managed DevOps Pool resource.", diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/main.test.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/main.test.bicep index c21a95f505..45332f3a95 100644 --- a/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/main.test.bicep +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/main.test.bicep @@ -10,25 +10,26 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-dev-ops-infrastructure.pool-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'mdpmin' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -@description('Required. Name of the Azure DevOps Organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') +@description('Required. Name of the Azure DevOps organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') @secure() param azureDevOpsOrganizationName string = '' +// The Managed DevOps Pools resource is not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + // ============ // // Dependencies // // ============ // module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { devCenterName: 'dep-${namePrefix}-dc-${serviceShort}' devCenterProjectName: 'dep-${namePrefix}-dcp-${serviceShort}' @@ -40,7 +41,7 @@ module nestedDependencies 'dependencies.bicep' = { // ================= // resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } // ============== // @@ -50,10 +51,10 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: resourceLocation + location: enforcedLocation agentProfile: { kind: 'Stateless' } diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/main.test.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/main.test.bicep index 7416f2934c..09b40200e5 100644 --- a/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/main.test.bicep +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/main.test.bicep @@ -11,16 +11,13 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-dev-ops-infrastructure.pool-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'mdpmax' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -@description('Required. Name of the Azure DevOps Organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') +@description('Required. Name of the Azure DevOps organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') @secure() param azureDevOpsOrganizationName string = '' @@ -32,12 +29,16 @@ param azureDevOpsProjectName string = '' @secure() param devOpsInfrastructureObjectID string = '' +// The Managed DevOps Pools resource is not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + // ============ // // Dependencies // // ============ // module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { devCenterName: 'dep-${namePrefix}-dc-${serviceShort}' devCenterProjectName: 'dep-${namePrefix}-dcp-${serviceShort}' @@ -51,7 +52,7 @@ module nestedDependencies 'dependencies.bicep' = { // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } // ============== // @@ -62,10 +63,10 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: resourceLocation + location: enforcedLocation agentProfile: { kind: 'Stateless' resourcePredictions: { diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/main.test.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/main.test.bicep index fdf015444f..20a04a3900 100644 --- a/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/main.test.bicep @@ -11,16 +11,13 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-dev-ops-infrastructure.pool-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'mdpwaf' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -@description('Required. Name of the Azure DevOps Organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') +@description('Required. Name of the Azure DevOps organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') @secure() param azureDevOpsOrganizationName string = '' @@ -32,12 +29,16 @@ param azureDevOpsProjectName string = '' @secure() param devOpsInfrastructureObjectID string = '' +// The Managed DevOps Pools resource is not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + // ============ // // Dependencies // // ============ // module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { devCenterName: 'dep-${namePrefix}-dc-${serviceShort}' devCenterProjectName: 'dep-${namePrefix}-dcp-${serviceShort}' @@ -51,7 +52,7 @@ module nestedDependencies 'dependencies.bicep' = { // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } // ============== // @@ -62,10 +63,10 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: resourceLocation + location: enforcedLocation agentProfile: { kind: 'Stateless' resourcePredictions: { From 0c002037f359c4e40ecf878f946ccf7ccd4916c9 Mon Sep 17 00:00:00 2001 From: Peter Budai Date: Fri, 27 Sep 2024 03:09:13 +0200 Subject: [PATCH 16/93] fix: Rename 'capacity' property to skuCapacity in the tests - `avm/res/sql/server` (#3318) Fixes #1324 ## Description ## Pipeline Reference | Pipeline | | -------- | | | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/sql/server/README.md | 8 ++++---- avm/res/sql/server/tests/e2e/max/main.test.bicep | 2 +- avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index 4f73df2fa8..dcc3f4e02f 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -270,7 +270,6 @@ module server 'br/public:avm/res/sql/server:' = { backupShortTermRetentionPolicy: { retentionDays: 14 } - capacity: 0 collation: 'SQL_Latin1_General_CP1_CI_AS' diagnosticSettings: [ { @@ -289,6 +288,7 @@ module server 'br/public:avm/res/sql/server:' = { licenseType: 'LicenseIncluded' maxSizeBytes: 34359738368 name: 'sqlsmaxdb-001' + skuCapacity: 0 skuName: 'ElasticPool' skuTier: 'GeneralPurpose' } @@ -438,7 +438,6 @@ module server 'br/public:avm/res/sql/server:' = { "backupShortTermRetentionPolicy": { "retentionDays": 14 }, - "capacity": 0, "collation": "SQL_Latin1_General_CP1_CI_AS", "diagnosticSettings": [ { @@ -457,6 +456,7 @@ module server 'br/public:avm/res/sql/server:' = { "licenseType": "LicenseIncluded", "maxSizeBytes": 34359738368, "name": "sqlsmaxdb-001", + "skuCapacity": 0, "skuName": "ElasticPool", "skuTier": "GeneralPurpose" } @@ -857,7 +857,6 @@ module server 'br/public:avm/res/sql/server:' = { backupShortTermRetentionPolicy: { retentionDays: 14 } - capacity: 0 collation: 'SQL_Latin1_General_CP1_CI_AS' diagnosticSettings: [ { @@ -876,6 +875,7 @@ module server 'br/public:avm/res/sql/server:' = { licenseType: 'LicenseIncluded' maxSizeBytes: 34359738368 name: 'sqlswafdb-001' + skuCapacity: 0 skuName: 'ElasticPool' skuTier: 'GeneralPurpose' } @@ -988,7 +988,6 @@ module server 'br/public:avm/res/sql/server:' = { "backupShortTermRetentionPolicy": { "retentionDays": 14 }, - "capacity": 0, "collation": "SQL_Latin1_General_CP1_CI_AS", "diagnosticSettings": [ { @@ -1007,6 +1006,7 @@ module server 'br/public:avm/res/sql/server:' = { "licenseType": "LicenseIncluded", "maxSizeBytes": 34359738368, "name": "sqlswafdb-001", + "skuCapacity": 0, "skuName": "ElasticPool", "skuTier": "GeneralPurpose" } diff --git a/avm/res/sql/server/tests/e2e/max/main.test.bicep b/avm/res/sql/server/tests/e2e/max/main.test.bicep index 662e8900fd..ec70abad1a 100644 --- a/avm/res/sql/server/tests/e2e/max/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/max/main.test.bicep @@ -125,7 +125,7 @@ module testDeployment '../../../main.bicep' = { collation: 'SQL_Latin1_General_CP1_CI_AS' skuTier: 'GeneralPurpose' skuName: 'ElasticPool' - capacity: 0 + skuCapacity: 0 maxSizeBytes: 34359738368 licenseType: 'LicenseIncluded' diagnosticSettings: [ diff --git a/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep b/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep index f444f7bf12..2f7e279f3b 100644 --- a/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep @@ -100,7 +100,7 @@ module testDeployment '../../../main.bicep' = { collation: 'SQL_Latin1_General_CP1_CI_AS' skuTier: 'GeneralPurpose' skuName: 'ElasticPool' - capacity: 0 + skuCapacity: 0 maxSizeBytes: 34359738368 licenseType: 'LicenseIncluded' diagnosticSettings: [ From 3c32902929de734daeeee6cc90070061922a2d85 Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:34:10 +0100 Subject: [PATCH 17/93] fix: Storage account readme regen (#3372) ## Description Fixing static validation pipeline run Recompiled json files to trigger module publishing, blocked for latest merge ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.storage.storage-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=users%2Feriqua%2Ffix-storage)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/storage/storage-account/README.md | 12 ++-- .../container/immutability-policy/main.json | 4 +- .../blob-service/container/main.json | 8 +-- .../storage-account/blob-service/main.json | 12 ++-- .../storage-account/file-service/README.md | 2 +- .../storage-account/file-service/main.json | 12 ++-- .../file-service/share/main.json | 8 +-- .../storage-account/local-user/README.md | 2 +- .../storage-account/local-user/main.json | 4 +- avm/res/storage/storage-account/main.json | 56 +++++++++---------- .../management-policy/main.json | 4 +- .../storage-account/queue-service/README.md | 4 +- .../storage-account/queue-service/main.json | 8 +-- .../queue-service/queue/README.md | 2 +- .../queue-service/queue/main.json | 4 +- .../storage-account/table-service/README.md | 4 +- .../storage-account/table-service/main.json | 8 +-- .../table-service/table/README.md | 2 +- .../table-service/table/main.json | 4 +- 19 files changed, 80 insertions(+), 80 deletions(-) diff --git a/avm/res/storage/storage-account/README.md b/avm/res/storage/storage-account/README.md index bafe70194f..310335b0d2 100644 --- a/avm/res/storage/storage-account/README.md +++ b/avm/res/storage/storage-account/README.md @@ -26,14 +26,14 @@ This module deploys a Storage Account. | `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/storageAccounts/fileServices) | +| `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/storageAccounts/localUsers) | +| `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/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `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 diff --git a/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json b/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json index e92ebe5e3f..1a92a67f27 100644 --- a/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json +++ b/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", diff --git a/avm/res/storage/storage-account/blob-service/container/main.json b/avm/res/storage/storage-account/blob-service/container/main.json index 92a5cbbbd0..1144d31c91 100644 --- a/avm/res/storage/storage-account/blob-service/container/main.json +++ b/avm/res/storage/storage-account/blob-service/container/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3558916747425087131" + "version": "0.30.23.60470", + "templateHash": "7740343838101895320" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -295,8 +295,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", diff --git a/avm/res/storage/storage-account/blob-service/main.json b/avm/res/storage/storage-account/blob-service/main.json index 944846b041..6ab964fa85 100644 --- a/avm/res/storage/storage-account/blob-service/main.json +++ b/avm/res/storage/storage-account/blob-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16657059190807174649" + "version": "0.30.23.60470", + "templateHash": "12887537147730330940" }, "name": "Storage Account blob Services", "description": "This module deploys a Storage Account Blob Service.", @@ -406,8 +406,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3558916747425087131" + "version": "0.30.23.60470", + "templateHash": "7740343838101895320" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -696,8 +696,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", diff --git a/avm/res/storage/storage-account/file-service/README.md b/avm/res/storage/storage-account/file-service/README.md index 3e9748cc67..af032effaa 100644 --- a/avm/res/storage/storage-account/file-service/README.md +++ b/avm/res/storage/storage-account/file-service/README.md @@ -13,7 +13,7 @@ This module deploys a Storage Account File Share Service. | 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) | -| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/fileServices) | +| `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 diff --git a/avm/res/storage/storage-account/file-service/main.json b/avm/res/storage/storage-account/file-service/main.json index 9375230d2f..3e4af3b534 100644 --- a/avm/res/storage/storage-account/file-service/main.json +++ b/avm/res/storage/storage-account/file-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1933197013743223154" + "version": "0.30.23.60470", + "templateHash": "3657184950062156101" }, "name": "Storage Account File Share Services", "description": "This module deploys a Storage Account File Share Service.", @@ -286,8 +286,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13477688809575027800" + "version": "0.30.23.60470", + "templateHash": "5694394509785243538" }, "name": "Storage Account File Shares", "description": "This module deploys a Storage Account File Share.", @@ -493,8 +493,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10820882302387746924" + "version": "0.30.23.60470", + "templateHash": "11498628270290452072" } }, "parameters": { diff --git a/avm/res/storage/storage-account/file-service/share/main.json b/avm/res/storage/storage-account/file-service/share/main.json index 90dc220560..6f8f81b2dc 100644 --- a/avm/res/storage/storage-account/file-service/share/main.json +++ b/avm/res/storage/storage-account/file-service/share/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13477688809575027800" + "version": "0.30.23.60470", + "templateHash": "5694394509785243538" }, "name": "Storage Account File Shares", "description": "This module deploys a Storage Account File Share.", @@ -212,8 +212,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10820882302387746924" + "version": "0.30.23.60470", + "templateHash": "11498628270290452072" } }, "parameters": { diff --git a/avm/res/storage/storage-account/local-user/README.md b/avm/res/storage/storage-account/local-user/README.md index f8476f2e7a..b311040c23 100644 --- a/avm/res/storage/storage-account/local-user/README.md +++ b/avm/res/storage/storage-account/local-user/README.md @@ -12,7 +12,7 @@ This module deploys a Storage Account Local User, which is used for SFTP authent | Resource Type | API Version | | :-- | :-- | -| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | ## Parameters diff --git a/avm/res/storage/storage-account/local-user/main.json b/avm/res/storage/storage-account/local-user/main.json index 3514e02614..8a19e11da9 100644 --- a/avm/res/storage/storage-account/local-user/main.json +++ b/avm/res/storage/storage-account/local-user/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18130658711251621530" + "version": "0.30.23.60470", + "templateHash": "14184905621772237225" }, "name": "Storage Account Local Users", "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", diff --git a/avm/res/storage/storage-account/main.json b/avm/res/storage/storage-account/main.json index 8120b7936e..90cce4364c 100644 --- a/avm/res/storage/storage-account/main.json +++ b/avm/res/storage/storage-account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8986504733456130232" + "version": "0.30.23.60470", + "templateHash": "6607893452071234065" }, "name": "Storage Accounts", "description": "This module deploys a Storage Account.", @@ -1937,8 +1937,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11289787713365096902" + "version": "0.30.23.60470", + "templateHash": "16749766572958481061" }, "name": "Storage Account Management Policies", "description": "This module deploys a Storage Account Management Policy.", @@ -2047,8 +2047,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18130658711251621530" + "version": "0.30.23.60470", + "templateHash": "14184905621772237225" }, "name": "Storage Account Local Users", "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", @@ -2265,8 +2265,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16657059190807174649" + "version": "0.30.23.60470", + "templateHash": "12887537147730330940" }, "name": "Storage Account blob Services", "description": "This module deploys a Storage Account Blob Service.", @@ -2666,8 +2666,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3558916747425087131" + "version": "0.30.23.60470", + "templateHash": "7740343838101895320" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -2956,8 +2956,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", @@ -3136,8 +3136,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1933197013743223154" + "version": "0.30.23.60470", + "templateHash": "3657184950062156101" }, "name": "Storage Account File Share Services", "description": "This module deploys a Storage Account File Share Service.", @@ -3417,8 +3417,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13477688809575027800" + "version": "0.30.23.60470", + "templateHash": "5694394509785243538" }, "name": "Storage Account File Shares", "description": "This module deploys a Storage Account File Share.", @@ -3624,8 +3624,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10820882302387746924" + "version": "0.30.23.60470", + "templateHash": "11498628270290452072" } }, "parameters": { @@ -3900,8 +3900,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9552908737955027812" + "version": "0.30.23.60470", + "templateHash": "6947504466788447852" }, "name": "Storage Account Queue Services", "description": "This module deploys a Storage Account Queue Service.", @@ -4145,8 +4145,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1992900679572007532" + "version": "0.30.23.60470", + "templateHash": "6090221832347220924" }, "name": "Storage Account Queues", "description": "This module deploys a Storage Account Queue.", @@ -4416,8 +4416,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15143318143658591417" + "version": "0.30.23.60470", + "templateHash": "6657632516379685259" }, "name": "Storage Account Table Services", "description": "This module deploys a Storage Account Table Service.", @@ -4658,8 +4658,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16017327978473583176" + "version": "0.30.23.60470", + "templateHash": "7397003163362434404" }, "name": "Storage Account Table", "description": "This module deploys a Storage Account Table.", @@ -4916,8 +4916,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "986606208324987345" + "version": "0.30.23.60470", + "templateHash": "12263717469683062316" } }, "definitions": { diff --git a/avm/res/storage/storage-account/management-policy/main.json b/avm/res/storage/storage-account/management-policy/main.json index c348d69daf..6acd0abce6 100644 --- a/avm/res/storage/storage-account/management-policy/main.json +++ b/avm/res/storage/storage-account/management-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11289787713365096902" + "version": "0.30.23.60470", + "templateHash": "16749766572958481061" }, "name": "Storage Account Management Policies", "description": "This module deploys a Storage Account Management Policy.", diff --git a/avm/res/storage/storage-account/queue-service/README.md b/avm/res/storage/storage-account/queue-service/README.md index ce773dbe3d..94ce2dacff 100644 --- a/avm/res/storage/storage-account/queue-service/README.md +++ b/avm/res/storage/storage-account/queue-service/README.md @@ -14,8 +14,8 @@ This module deploys a Storage Account Queue Service. | :-- | :-- | | `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/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | +| `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 diff --git a/avm/res/storage/storage-account/queue-service/main.json b/avm/res/storage/storage-account/queue-service/main.json index 00065e2abe..6fc76d0b47 100644 --- a/avm/res/storage/storage-account/queue-service/main.json +++ b/avm/res/storage/storage-account/queue-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9552908737955027812" + "version": "0.30.23.60470", + "templateHash": "6947504466788447852" }, "name": "Storage Account Queue Services", "description": "This module deploys a Storage Account Queue Service.", @@ -250,8 +250,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1992900679572007532" + "version": "0.30.23.60470", + "templateHash": "6090221832347220924" }, "name": "Storage Account Queues", "description": "This module deploys a Storage Account Queue.", diff --git a/avm/res/storage/storage-account/queue-service/queue/README.md b/avm/res/storage/storage-account/queue-service/queue/README.md index ccfbd4b635..140ca97388 100644 --- a/avm/res/storage/storage-account/queue-service/queue/README.md +++ b/avm/res/storage/storage-account/queue-service/queue/README.md @@ -13,7 +13,7 @@ This module deploys a Storage Account Queue. | 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/storageAccounts/queueServices/queues) | +| `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 diff --git a/avm/res/storage/storage-account/queue-service/queue/main.json b/avm/res/storage/storage-account/queue-service/queue/main.json index 8bea12f90e..2aad9fefb2 100644 --- a/avm/res/storage/storage-account/queue-service/queue/main.json +++ b/avm/res/storage/storage-account/queue-service/queue/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1992900679572007532" + "version": "0.30.23.60470", + "templateHash": "6090221832347220924" }, "name": "Storage Account Queues", "description": "This module deploys a Storage Account Queue.", diff --git a/avm/res/storage/storage-account/table-service/README.md b/avm/res/storage/storage-account/table-service/README.md index f4a529a253..7f65d890d0 100644 --- a/avm/res/storage/storage-account/table-service/README.md +++ b/avm/res/storage/storage-account/table-service/README.md @@ -14,8 +14,8 @@ This module deploys a Storage Account Table Service. | :-- | :-- | | `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/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `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 diff --git a/avm/res/storage/storage-account/table-service/main.json b/avm/res/storage/storage-account/table-service/main.json index 5582b11c4a..df8cac0dbd 100644 --- a/avm/res/storage/storage-account/table-service/main.json +++ b/avm/res/storage/storage-account/table-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15143318143658591417" + "version": "0.30.23.60470", + "templateHash": "6657632516379685259" }, "name": "Storage Account Table Services", "description": "This module deploys a Storage Account Table Service.", @@ -247,8 +247,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16017327978473583176" + "version": "0.30.23.60470", + "templateHash": "7397003163362434404" }, "name": "Storage Account Table", "description": "This module deploys a Storage Account Table.", diff --git a/avm/res/storage/storage-account/table-service/table/README.md b/avm/res/storage/storage-account/table-service/table/README.md index 4009c666b3..63e5d835bf 100644 --- a/avm/res/storage/storage-account/table-service/table/README.md +++ b/avm/res/storage/storage-account/table-service/table/README.md @@ -13,7 +13,7 @@ This module deploys a Storage Account Table. | 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/storageAccounts/tableServices/tables) | +| `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 diff --git a/avm/res/storage/storage-account/table-service/table/main.json b/avm/res/storage/storage-account/table-service/table/main.json index 0476ee247e..15dc63d03b 100644 --- a/avm/res/storage/storage-account/table-service/table/main.json +++ b/avm/res/storage/storage-account/table-service/table/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16017327978473583176" + "version": "0.30.23.60470", + "templateHash": "7397003163362434404" }, "name": "Storage Account Table", "description": "This module deploys a Storage Account Table.", From 74f1839e457a394954c18fae201662dfbf8ba15b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 09:18:34 +0100 Subject: [PATCH 18/93] fix: bump github/codeql-action from 3.25.15 to 3.26.9 (#3360) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.15 to 3.26.9.

Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

Note that the only difference between v2 and v3 of the CodeQL Action is the node version they support, with v3 running on node 20 while we continue to release v2 to support running on node 16. For example 3.22.11 was the first v3 release and is functionally identical to 2.22.11. This approach ensures an easy way to track exactly which features are included in different versions, indicated by the minor and patch version numbers.

[UNRELEASED]

No user facing changes.

3.26.9 - 24 Sep 2024

No user facing changes.

3.26.8 - 19 Sep 2024

  • Update default CodeQL bundle version to 2.19.0. #2483

3.26.7 - 13 Sep 2024

  • Update default CodeQL bundle version to 2.18.4. #2471

3.26.6 - 29 Aug 2024

  • Update default CodeQL bundle version to 2.18.3. #2449

3.26.5 - 23 Aug 2024

  • Fix an issue where the csrutil system call used for telemetry would fail on MacOS ARM machines with System Integrity Protection disabled. #2441

3.26.4 - 21 Aug 2024

  • Deprecation: The add-snippets input on the analyze Action is deprecated and will be removed in the first release in August 2025. #2436
  • Fix an issue where the disk usage system call used for telemetry would fail on MacOS ARM machines with System Integrity Protection disabled, and then surface a warning. The system call is now disabled for these machines. #2434

3.26.3 - 19 Aug 2024

  • Fix an issue where the CodeQL Action could not write diagnostic messages on Windows. This issue did not impact analysis quality. #2430

3.26.2 - 14 Aug 2024

  • Update default CodeQL bundle version to 2.18.2. #2417

3.26.1 - 13 Aug 2024

No user facing changes.

3.26.0 - 06 Aug 2024

  • Deprecation: Swift analysis on Ubuntu runner images is no longer supported. Please migrate to a macOS runner if this affects you. #2403

... (truncated)

Commits
  • 461ef6c Merge pull request #2503 from github/update-v3.26.9-f861efb2b
  • 00b1146 Update changelog for v3.26.9
  • f861efb Merge pull request #2498 from github/dependabot/npm_and_yarn/npm-9874b37b58
  • 426821d Merge pull request #2485 from github/dependabot/github_actions/actions-a88a8c...
  • 07e8133 Merge pull request #2501 from github/henrymercer/missing-autobuild-config-error
  • e0a151e Fix inconsistency in autobuild error tracking
  • 6b0ce4e revert eslint-plugin-import to 2.29.1
  • 07fd497 Merge branch 'main' into dependabot/github_actions/actions-a88a8c5a24
  • 2cddcb1 Merge pull request #2499 from github/aeisenberg/no-upload-sarif
  • 6225a95 Don't upload during cancelled jobs
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=3.25.15&new-version=3.26.9)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/platform.ossf-scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/platform.ossf-scorecard.yml b/.github/workflows/platform.ossf-scorecard.yml index 5c37e5fc09..386dca42a6 100644 --- a/.github/workflows/platform.ossf-scorecard.yml +++ b/.github/workflows/platform.ossf-scorecard.yml @@ -68,6 +68,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: sarif_file: results.sarif From 95ee1a36aac870b74568a78361ee68a488d4784c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 09:22:27 +0100 Subject: [PATCH 19/93] fix: bump actions/upload-artifact from 4.3.5 to 4.4.0 (#3155) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.5 to 4.4.0.
Release notes

Sourced from actions/upload-artifact's releases.

v4.4.0

Notice: Breaking Changes :warning:

We will no longer include hidden files and folders by default in the upload-artifact action of this version. This reduces the risk that credentials are accidentally uploaded into artifacts. Customers who need to continue to upload these files can use a new option, include-hidden-files, to continue to do so.

See "Notice of upcoming deprecations and breaking changes in GitHub Actions runners" changelog and this issue for more details.

What's Changed

Full Changelog: https://github.com/actions/upload-artifact/compare/v4.3.6...v4.4.0

v4.3.6

What's Changed

Full Changelog: https://github.com/actions/upload-artifact/compare/v4...v4.3.6

Commits
  • 5076954 Merge pull request #598 from actions/joshmgross/exclude-hidden-files
  • d52396a Add a warning about enabling include-hidden-files
  • 710f362 Remove "merged" from include-hidden-files input description
  • 3b315f2 npm run release again 🙂
  • 3be2180 Remove another trailing comma
  • 453e8d0 Update glob license
  • 0a398c1 npm run release
  • a0c40cf Update to latest @actions/glob and fix tests
  • acb59e4 lint
  • cb6558b Exclude hidden files by default
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=4.3.5&new-version=4.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jack Tracey <41163455+jtracey93@users.noreply.github.com> --- .github/workflows/platform.ossf-scorecard.yml | 2 +- .github/workflows/platform.publish-module-index-json.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/platform.ossf-scorecard.yml b/.github/workflows/platform.ossf-scorecard.yml index 386dca42a6..cfbec6ff1f 100644 --- a/.github/workflows/platform.ossf-scorecard.yml +++ b/.github/workflows/platform.ossf-scorecard.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4.3.5 + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/platform.publish-module-index-json.yml b/.github/workflows/platform.publish-module-index-json.yml index b6a510c1f0..9c140c7102 100644 --- a/.github/workflows/platform.publish-module-index-json.yml +++ b/.github/workflows/platform.publish-module-index-json.yml @@ -74,7 +74,7 @@ jobs: } - name: Upload artifacts - uses: actions/upload-artifact@v4.3.5 + uses: actions/upload-artifact@v4.4.0 with: name: publish-module-index-json-artifacts path: | From abd95ca57517fe7b77b0c756e285c1ad5d029ff5 Mon Sep 17 00:00:00 2001 From: Luke Snoddy <37806411+lsnoddy@users.noreply.github.com> Date: Fri, 27 Sep 2024 06:51:17 -0500 Subject: [PATCH 20/93] fix: Added fixed uksouth and ukwest locations for `avm.res.network.trafficmanagerprofile` (#3354) ## Description This pull request introduces fixed locations (uksouth and ukwest) used to deploy App Service plans in the waf test case due to sku family limitations Fixes #3205 Closes #3205 ## Pipeline Reference | Pipeline | | -------- | [![avm.res.network.trafficmanagerprofile](https://github.com/lsnoddy/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml/badge.svg?branch=users%2Flsnoddy%2Ftrafficmanagerprovile)](https://github.com/lsnoddy/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml) | | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- .../network/trafficmanagerprofile/README.md | 8 +++--- .../network/trafficmanagerprofile/main.json | 4 +-- .../tests/e2e/waf-aligned/main.test.bicep | 27 ++++++++++--------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/avm/res/network/trafficmanagerprofile/README.md b/avm/res/network/trafficmanagerprofile/README.md index c7dfa7d65c..11fa33f627 100644 --- a/avm/res/network/trafficmanagerprofile/README.md +++ b/avm/res/network/trafficmanagerprofile/README.md @@ -257,7 +257,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:' endpointStatus: 'Enabled' priority: 1 targetResourceId: '' @@ -268,7 +268,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:' endpointStatus: 'Enabled' priority: 2 targetResourceId: '' @@ -334,7 +334,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:", "endpointStatus": "Enabled", "priority": 1, "targetResourceId": "", @@ -345,7 +345,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:", "endpointStatus": "Enabled", "priority": 2, "targetResourceId": "", diff --git a/avm/res/network/trafficmanagerprofile/main.json b/avm/res/network/trafficmanagerprofile/main.json index 275f4d0955..1b1e35e937 100644 --- a/avm/res/network/trafficmanagerprofile/main.json +++ b/avm/res/network/trafficmanagerprofile/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2090813965996228671" + "version": "0.30.23.60470", + "templateHash": "5539048151819308545" }, "name": "Traffic Manager Profiles", "description": "This module deploys a Traffic Manager Profile.", diff --git a/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep index 32d82ac36b..3394fe0e75 100644 --- a/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep @@ -11,8 +11,11 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-network.trafficmanagerprofiles-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +#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' @@ -28,21 +31,21 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation01 } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation01)}-nestedDependencies' params: { managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' - location: resourceLocation + 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: 'eastus' - location02: 'westus' + location01: enforcedLocation01 + location02: enforcedLocation02 } } @@ -50,13 +53,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + 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: resourceLocation + location: enforcedLocation01 } } @@ -67,7 +70,7 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation01)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' location: 'global' @@ -107,7 +110,7 @@ module testDeployment '../../../main.bicep' = [ targetResourceId: nestedDependencies.outputs.webApp01ResourceId weight: 1 priority: 1 - endpointLocation: 'eastus' + endpointLocation: '${enforcedLocation01}' endpointStatus: 'Enabled' } } @@ -118,7 +121,7 @@ module testDeployment '../../../main.bicep' = [ targetResourceId: nestedDependencies.outputs.webApp02ResourceId weight: 1 priority: 2 - endpointLocation: 'westus' + endpointLocation: '${enforcedLocation02}' endpointStatus: 'Enabled' } } From 0463edbfbac951c9c9f87bebdcb10cdf8691cba6 Mon Sep 17 00:00:00 2001 From: Kris Baranek <20225789+krbar@users.noreply.github.com> Date: Sat, 28 Sep 2024 02:42:31 +0200 Subject: [PATCH 21/93] test: `avm/res/network/service-endpoint-policy` - add RBAC test (#3182) ## Description - added `max` test case with roleAssignments test - moved `locks` test from `waf-aligned` to `max` - removed unnecessary comment lines in test cases ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.service-endpoint-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml/badge.svg?branch=users%2Fkrbar%2FsvcEpPolicy)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../network/service-endpoint-policy/README.md | 111 +++++++++++++++++- .../tests/e2e/defaults/main.test.bicep | 3 - .../tests/e2e/max/dependencies.bicep | 13 ++ .../tests/e2e/max/main.test.bicep | 87 ++++++++++++++ .../tests/e2e/waf-aligned/main.test.bicep | 7 -- 5 files changed, 206 insertions(+), 15 deletions(-) create mode 100644 avm/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep diff --git a/avm/res/network/service-endpoint-policy/README.md b/avm/res/network/service-endpoint-policy/README.md index 7d1097c4b2..2fb4267d72 100644 --- a/avm/res/network/service-endpoint-policy/README.md +++ b/avm/res/network/service-endpoint-policy/README.md @@ -27,7 +27,8 @@ The following section provides usage examples for the module, which were used to >**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) -- [WAF-aligned](#example-2-waf-aligned) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) ### Example 1: _Using only defaults_ @@ -77,9 +78,9 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

-### Example 2: _WAF-aligned_ +### Example 2: _Using large parameter set_ -This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. +This instance deploys the module with most of its features enabled.

@@ -91,13 +92,32 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy: name: 'serviceEndpointPolicyDeployment' params: { // Required parameters - name: 'nsepwaf001' + 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' @@ -121,7 +141,7 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy: "parameters": { // Required parameters "name": { - "value": "nsepwaf001" + "value": "nsepmax001" }, // Non-required parameters "location": { @@ -133,6 +153,87 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy: "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" + } + } + } +} +``` + +
+

+ +### 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 Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nsepwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, "tags": { "value": { "Environment": "Non-Prod", diff --git a/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep index ba587c2c4d..6a594af1c8 100644 --- a/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep @@ -9,14 +9,12 @@ metadata description = 'This instance deploys the module with the minimum set of @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.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.') -// 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 = 'nsepmin' @description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') @@ -42,7 +40,6 @@ module testDeployment '../../../main.bicep' = [ scope: resourceGroup name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { - // You parameters go here name: '${namePrefix}${serviceShort}001' location: resourceLocation } diff --git a/avm/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..7b3d4e8fb0 --- /dev/null +++ b/avm/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/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..43504b4599 --- /dev/null +++ b/avm/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/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep index 0076f59669..b2c6f19281 100644 --- a/avm/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep @@ -9,14 +9,12 @@ metadata description = 'This instance deploys the module in alignment with the b @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.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.') -// 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 = 'nsepwaf' @description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') @@ -42,13 +40,8 @@ module testDeployment '../../../main.bicep' = [ scope: resourceGroup name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { - // You parameters go here name: '${namePrefix}${serviceShort}001' location: resourceLocation - lock: { - kind: 'CanNotDelete' - name: 'myCustomLockName' - } tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' From 9ab65b20e7c76dc2cb6fafbaa3ec2a368a9f4675 Mon Sep 17 00:00:00 2001 From: Seif Bassem <38246040+sebassem@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:23:32 +0300 Subject: [PATCH 22/93] fix: Implement resiliency by default (#3370) ## Description Default to zone-redundant SKUs Default to zone-redundant Public IP fixes #3369 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.virtual-network-gateway](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml/badge.svg?branch=avm-resiliency-vnetGw)](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [X] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --- .../network/virtual-network-gateway/README.md | 170 ++++++++++-------- .../virtual-network-gateway/main.bicep | 27 ++- .../network/virtual-network-gateway/main.json | 17 +- .../tests/e2e/vpn-no-az/main.test.bicep | 3 +- 4 files changed, 115 insertions(+), 102 deletions(-) diff --git a/avm/res/network/virtual-network-gateway/README.md b/avm/res/network/virtual-network-gateway/README.md index 644177396e..85c0d4ad2e 100644 --- a/avm/res/network/virtual-network-gateway/README.md +++ b/avm/res/network/virtual-network-gateway/README.md @@ -62,7 +62,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgavpn001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters domainNameLabel: [ @@ -74,6 +73,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnClientAadConfiguration: { aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' aadIssuer: '' @@ -114,9 +114,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgavpn001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -136,6 +133,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnClientAadConfiguration": { "value": { "aadAudience": "41b23e61-6c1e-4545-b367-cd054e0ed4b4", @@ -178,7 +178,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgaab001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -195,6 +194,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } @@ -225,9 +225,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgaab001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -262,6 +259,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnGatewayGeneration": { "value": "Generation2" }, @@ -302,7 +302,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgaaa001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -319,6 +318,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } @@ -357,9 +357,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgaaa001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -394,6 +391,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnGatewayGeneration": { "value": "Generation2" }, @@ -426,7 +426,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgaa001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -443,6 +442,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } @@ -473,9 +473,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgaa001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -510,6 +507,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnGatewayGeneration": { "value": "Generation2" }, @@ -547,7 +547,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgapb001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -564,6 +563,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } @@ -599,9 +599,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgapb001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -636,6 +633,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnGatewayGeneration": { "value": "Generation2" }, @@ -668,7 +668,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgap001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -685,6 +684,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } @@ -715,9 +715,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgap001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -752,6 +749,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnGatewayGeneration": { "value": "Generation2" }, @@ -784,7 +784,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgmin001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters location: '' @@ -793,6 +792,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' } } ``` @@ -821,9 +821,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgmin001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -837,6 +834,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2, 3 ] + }, + "skuName": { + "value": "VpnGw2AZ" } } } @@ -864,7 +864,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'ExpressRoute' name: 'nvger001' - skuName: 'ErGw1AZ' vNetResourceId: '' // Non-required parameters domainNameLabel: [ @@ -877,6 +876,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'ErGw1AZ' } } ``` @@ -905,9 +905,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvger001" }, - "skuName": { - "value": "ErGw1AZ" - }, "vNetResourceId": { "value": "" }, @@ -929,6 +926,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2, 3 ] + }, + "skuName": { + "value": "ErGw1AZ" } } } @@ -965,7 +965,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgmax001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -1053,6 +1052,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: roleDefinitionIdOrName: '' } ] + skuName: 'VpnGw2AZ' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -1097,9 +1097,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgmax001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -1213,6 +1210,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -1252,10 +1252,11 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgnaz001' - skuName: 'VpnGw1' vNetResourceId: '' // Non-required parameters location: '' + publicIpZones: [] + skuName: 'VpnGw1' } } ``` @@ -1284,15 +1285,18 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgnaz001" }, - "skuName": { - "value": "VpnGw1" - }, "vNetResourceId": { "value": "" }, // Non-required parameters "location": { "value": "" + }, + "publicIpZones": { + "value": [] + }, + "skuName": { + "value": "VpnGw1" } } } @@ -1320,7 +1324,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgvpn001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -1337,6 +1340,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } @@ -1367,9 +1371,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgvpn001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -1404,6 +1405,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnGatewayGeneration": { "value": "Generation2" }, @@ -1445,7 +1449,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } gatewayType: 'Vpn' name: 'nvgmwaf001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true @@ -1514,6 +1517,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -1558,9 +1562,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "name": { "value": "nvgmwaf001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, @@ -1653,6 +1654,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -1682,7 +1686,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: | [`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** @@ -1709,6 +1712,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: | [`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. | +| [`skuName`](#parameter-skuname) | string | The SKU of the Gateway. | | [`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. | @@ -1743,35 +1747,6 @@ Specifies the Virtual Network Gateway name. - Required: Yes - Type: string -### Parameter: `skuName` - -The SKU of the Gateway. - -- Required: Yes -- Type: string -- 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. @@ -2233,7 +2208,14 @@ Specifies the zones of the Public IP address. Basic IP SKU does not support Avai - Required: No - Type: array -- Default: `[]` +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` ### Parameter: `roleAssignments` @@ -2339,6 +2321,36 @@ The principal type of the assigned principal ID. ] ``` +### 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: `tags` Tags of the resource. diff --git a/avm/res/network/virtual-network-gateway/main.bicep b/avm/res/network/virtual-network-gateway/main.bicep index 15b0247f69..4cf0d87c15 100644 --- a/avm/res/network/virtual-network-gateway/main.bicep +++ b/avm/res/network/virtual-network-gateway/main.bicep @@ -15,7 +15,11 @@ param gatewayPipName string = '${name}-pip1' param publicIPPrefixResourceId string = '' @description('Optional. Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones.') -param publicIpZones array = [] +param publicIpZones array = [ + 1 + 2 + 3 +] @description('Optional. DNS name(s) of the Public IP resource(s). If you enabled active-active configuration, 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 = [] @@ -35,7 +39,7 @@ param gatewayType string ]) param vpnGatewayGeneration string = 'None' -@description('Required. The SKU of the Gateway.') +@description('Optional. The SKU of the Gateway.') @allowed([ 'Basic' 'VpnGw1' @@ -55,7 +59,7 @@ param vpnGatewayGeneration string = 'None' 'ErGw2AZ' 'ErGw3AZ' ]) -param skuName string +param skuName string = (gatewayType == 'VPN') ? 'VpnGw1AZ' : 'ErGw1AZ' @description('Optional. Specifies the VPN type.') @allowed([ @@ -175,7 +179,6 @@ var bgpSettingsVar = isActiveActive ] } - // Potential IP configurations (active-active vs active-passive) var ipConfiguration = isActiveActive ? [ @@ -554,53 +557,45 @@ type diagnosticSettingType = { }[]? type activePassiveNoBgpType = { - clusterMode: 'activePassiveNoBgp' - } type activeActiveNoBgpType = { - clusterMode: 'activeActiveNoBgp' @description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') activeGatewayPipName: 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? + 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. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') activeGatewayPipName: 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? + 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/res/network/virtual-network-gateway/main.json b/avm/res/network/virtual-network-gateway/main.json index 5e1b4bdf4c..5badcfef95 100644 --- a/avm/res/network/virtual-network-gateway/main.json +++ b/avm/res/network/virtual-network-gateway/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "973776533492793692" + "version": "0.30.23.60470", + "templateHash": "6347373659148864152" }, "name": "Virtual Network Gateways", "description": "This module deploys a Virtual Network Gateway.", @@ -388,7 +388,11 @@ }, "publicIpZones": { "type": "array", - "defaultValue": [], + "defaultValue": [ + 1, + 2, + 3 + ], "metadata": { "description": "Optional. Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones." } @@ -424,6 +428,7 @@ }, "skuName": { "type": "string", + "defaultValue": "[if(equals(parameters('gatewayType'), 'VPN'), 'VpnGw1AZ', 'ErGw1AZ')]", "allowedValues": [ "Basic", "VpnGw1", @@ -444,7 +449,7 @@ "ErGw3AZ" ], "metadata": { - "description": "Required. The SKU of the Gateway." + "description": "Optional. The SKU of the Gateway." } }, "vpnType": { @@ -1455,8 +1460,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "915174536118171652" + "version": "0.30.23.60470", + "templateHash": "15500017864202979057" }, "name": "VPN Gateway NAT Rules", "description": "This module deploys a Virtual Network Gateway NAT Rule.", diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep index 514b8429ab..fc3410af52 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep @@ -56,8 +56,9 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' skuName: 'VpnGw1' gatewayType: 'Vpn' + publicIpZones: [] vNetResourceId: nestedDependencies.outputs.vnetResourceId - clusterSettings:{ + clusterSettings: { clusterMode: 'activePassiveNoBgp' } } From 720edc039c8590abc785392cc209407c93f8671c Mon Sep 17 00:00:00 2001 From: Seif Bassem <38246040+sebassem@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:12:22 +0300 Subject: [PATCH 23/93] fix: updating virtualNetwork API for LZ network resource (#3366) ## Description Bump the LZ virtual network resource to avoid subnet deletion on PUT requests Fixes #3330 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.lz.sub-vending](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml/badge.svg?branch=avm-ptn-sub-vending-network-api)](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/lz/sub-vending/README.md | 20 +- avm/ptn/lz/sub-vending/main.json | 1341 ++++++++++++----- .../modules/subResourceWrapper.bicep | 37 +- 3 files changed, 1030 insertions(+), 368 deletions(-) diff --git a/avm/ptn/lz/sub-vending/README.md b/avm/ptn/lz/sub-vending/README.md index d765a73bfc..d1bea9021b 100644 --- a/avm/ptn/lz/sub-vending/README.md +++ b/avm/ptn/lz/sub-vending/README.md @@ -25,9 +25,9 @@ This module deploys a subscription to accelerate deployment of landing zones. Fo | `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Network/virtualHubs/hubVirtualNetworkConnections` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualHubs/hubVirtualNetworkConnections) | -| `Microsoft.Network/virtualNetworks` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualNetworks) | -| `Microsoft.Network/virtualNetworks/subnets` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualNetworks/subnets) | -| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualNetworks/virtualNetworkPeerings) | +| `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | +| `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/virtualNetworkPeerings) | | `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2023-08-01/deploymentScripts) | | `Microsoft.Resources/resourceGroups` | [2021-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2021-04-01/resourceGroups) | | `Microsoft.Resources/tags` | [2019-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/tags) | @@ -35,14 +35,14 @@ This module deploys a subscription to accelerate deployment of landing zones. Fo | `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/storageAccounts/fileServices) | +| `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/storageAccounts/localUsers) | +| `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/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `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) | | `Microsoft.Subscription/aliases` | [2021-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Subscription/2021-10-01/aliases) | ## Usage examples @@ -949,7 +949,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | `br/public:avm/ptn/authorization/role-assignment:0.1.0` | Remote reference | | `br/public:avm/res/managed-identity/user-assigned-identity:0.2.2` | Remote reference | | `br/public:avm/res/network/network-security-group:0.3.0` | Remote reference | -| `br/public:avm/res/network/virtual-network:0.1.7` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | | `br/public:avm/res/resources/deployment-script:0.2.3` | Remote reference | | `br/public:avm/res/resources/resource-group:0.2.4` | Remote reference | | `br/public:avm/res/storage/storage-account:0.9.1` | Remote reference | diff --git a/avm/ptn/lz/sub-vending/main.json b/avm/ptn/lz/sub-vending/main.json index 35687dd6ea..e42574e3c1 100644 --- a/avm/ptn/lz/sub-vending/main.json +++ b/avm/ptn/lz/sub-vending/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2409780926109914899" + "version": "0.30.23.60470", + "templateHash": "2343164809013150587" }, "name": "Sub-vending", "description": "This module deploys a subscription to accelerate deployment of landing zones. For more information on how to use it, please visit this [Wiki](https://github.com/Azure/bicep-lz-vending/wiki).", @@ -445,8 +445,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3759867594724381121" + "version": "0.30.23.60470", + "templateHash": "1611270751895734589" } }, "parameters": { @@ -652,8 +652,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10394721304346895394" + "version": "0.30.23.60470", + "templateHash": "12288692280280036332" }, "name": "`/subResourcesWrapper/deploy.bicep` Parameters", "description": "This module is used by the [`bicep-lz-vending`](https://aka.ms/sub-vending/bicep) module to help orchestrate the deployment", @@ -1028,8 +1028,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13961984943235030681" + "version": "0.30.23.60470", + "templateHash": "15074465703139369012" } }, "parameters": { @@ -1086,8 +1086,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6592820624705341105" + "version": "0.30.23.60470", + "templateHash": "15410141635305926698" } }, "parameters": { @@ -1146,8 +1146,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3589833223987550845" + "version": "0.30.23.60470", + "templateHash": "5472979603320584709" } }, "parameters": { @@ -1202,8 +1202,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15687156082548283745" + "version": "0.30.23.60470", + "templateHash": "11343593259864722989" } }, "parameters": { @@ -1280,8 +1280,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2885361202003966670" + "version": "0.30.23.60470", + "templateHash": "13884963778440627255" } }, "parameters": { @@ -1335,8 +1335,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4327209924100539632" + "version": "0.30.23.60470", + "templateHash": "4428652978548820109" } }, "parameters": { @@ -1915,8 +1915,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6592820624705341105" + "version": "0.30.23.60470", + "templateHash": "15410141635305926698" } }, "parameters": { @@ -1975,8 +1975,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3589833223987550845" + "version": "0.30.23.60470", + "templateHash": "5472979603320584709" } }, "parameters": { @@ -2031,8 +2031,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15687156082548283745" + "version": "0.30.23.60470", + "templateHash": "11343593259864722989" } }, "parameters": { @@ -2109,8 +2109,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2885361202003966670" + "version": "0.30.23.60470", + "templateHash": "13884963778440627255" } }, "parameters": { @@ -2164,8 +2164,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4327209924100539632" + "version": "0.30.23.60470", + "templateHash": "4428652978548820109" } }, "parameters": { @@ -2285,7 +2285,7 @@ "ddosProtectionPlanResourceId": { "value": "[parameters('virtualNetworkDdosPlanResourceId')]" }, - "peerings": "[if(and(and(and(and(and(and(parameters('virtualNetworkEnabled'), parameters('virtualNetworkPeeringEnabled')), not(empty(variables('hubVirtualNetworkResourceIdChecked')))), not(empty(parameters('virtualNetworkName')))), not(empty(parameters('virtualNetworkAddressSpace')))), not(empty(parameters('virtualNetworkLocation')))), not(empty(parameters('virtualNetworkResourceGroupName')))), createObject('value', createArray(createObject('allowForwardedTraffic', true(), 'allowVirtualNetworkAccess', true(), 'allowGatewayTransit', false(), 'useRemoteGateways', parameters('virtualNetworkUseRemoteGateways'), 'remotePeeringEnabled', parameters('virtualNetworkPeeringEnabled'), 'remoteVirtualNetworkId', variables('hubVirtualNetworkResourceIdChecked'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringAllowGatewayTransit', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", + "peerings": "[if(and(and(and(and(and(and(parameters('virtualNetworkEnabled'), parameters('virtualNetworkPeeringEnabled')), not(empty(variables('hubVirtualNetworkResourceIdChecked')))), not(empty(parameters('virtualNetworkName')))), not(empty(parameters('virtualNetworkAddressSpace')))), not(empty(parameters('virtualNetworkLocation')))), not(empty(parameters('virtualNetworkResourceGroupName')))), createObject('value', createArray(createObject('remoteVirtualNetworkResourceId', variables('hubVirtualNetworkResourceIdChecked'), 'allowForwardedTraffic', true(), 'allowVirtualNetworkAccess', true(), 'allowGatewayTransit', false(), 'useRemoteGateways', parameters('virtualNetworkUseRemoteGateways'), 'remotePeeringEnabled', parameters('virtualNetworkPeeringEnabled'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringAllowGatewayTransit', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', null()))]", "enableTelemetry": { "value": "[parameters('enableTelemetry')]" } @@ -2297,8 +2297,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16637670595978489426" + "version": "0.29.47.4906", + "templateHash": "15949466154563447171" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -2335,6 +2335,13 @@ "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": { @@ -2515,6 +2522,242 @@ } }, "nullable": true + }, + "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" + ], + "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": { + "$ref": "#/definitions/roleAssignmentType", + "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." + } + } + } } }, "parameters": { @@ -2537,32 +2780,48 @@ "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", - "defaultValue": [], + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, "metadata": { "description": "Optional. An Array of subnets to deploy to the Virtual Network." } }, "dnsServers": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { "description": "Optional. DNS Servers associated to the Virtual Network." } }, "ddosProtectionPlanResourceId": { "type": "string", - "defaultValue": "", + "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", - "defaultValue": [], + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, "metadata": { - "description": "Optional. Virtual Network Peerings configurations." + "description": "Optional. Virtual Network Peering configurations." } }, "vnetEncryption": { @@ -2622,15 +2881,29 @@ "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -2638,8 +2911,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.1.7', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2657,42 +2930,21 @@ }, "virtualNetwork": { "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-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')]" }, + "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())]" + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" } }, "virtualNetwork_lock": { @@ -2753,20 +3005,20 @@ "virtualNetwork_roleAssignments": { "copy": { "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -2775,7 +3027,7 @@ "virtualNetwork_subnets": { "copy": { "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", "mode": "serial", "batchSize": 1 }, @@ -2792,23 +3044,50 @@ "value": "[parameters('name')]" }, "name": { - "value": "[parameters('subnets')[copyIndex()].name]" + "value": "[coalesce(parameters('subnets'), createArray())[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()))]" + "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#", @@ -2817,8 +3096,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "9634407864982934565" + "version": "0.29.47.4906", + "templateHash": "5699372618313647761" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -2830,6 +3109,13 @@ "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": { @@ -2896,7 +3182,7 @@ "name": { "type": "string", "metadata": { - "description": "Optional. The Name of the subnet resource." + "description": "Requird. The Name of the subnet resource." } }, "virtualNetworkName": { @@ -2907,41 +3193,45 @@ }, "addressPrefix": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The address prefix for the subnet." + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." } }, "networkSecurityGroupResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the network security group to assign to the subnet." } }, "routeTableResourceId": { "type": "string", - "defaultValue": "", + "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." } }, - "delegations": { - "type": "array", - "defaultValue": [], + "delegation": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. The delegations to enable on the subnet." + "description": "Optional. The delegation to enable on the subnet." } }, "natGatewayResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." } @@ -2955,7 +3245,7 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." } }, "privateLinkServiceNetworkPolicies": { @@ -2967,28 +3257,42 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." } }, "addressPrefixes": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. List of address prefixes for the subnet." + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." } }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "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." } }, - "ipAllocations": { + "applicationGatewayIPConfigurations": { "type": "array", "defaultValue": [], "metadata": { - "description": "Optional. Array of IpAllocation which reference this subnet." + "description": "Optional. Application gateway IP configurations of virtual network resource." } }, "serviceEndpointPolicies": { @@ -3006,12 +3310,19 @@ } }, "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')]", + "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')]" } }, @@ -3019,26 +3330,35 @@ "virtualNetwork": { "existing": true, "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[parameters('virtualNetworkName')]" }, "subnet": { "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2023-11-01", + "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())]", - "serviceEndpoints": "[parameters('serviceEndpoints')]", - "delegations": "[parameters('delegations')]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", "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')]" + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" }, "dependsOn": [ "virtualNetwork" @@ -3047,20 +3367,20 @@ "subnet_roleAssignments": { "copy": { "name": "subnet_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "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": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -3089,19 +3409,19 @@ }, "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" }, - "subnetAddressPrefix": { + "addressPrefix": { "type": "string", "metadata": { "description": "The address prefix for the subnet." }, - "value": "[reference('subnet').addressPrefix]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" }, - "subnetAddressPrefixes": { + "addressPrefixes": { "type": "array", "metadata": { "description": "List of address prefixes for the subnet." }, - "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" } } } @@ -3113,7 +3433,7 @@ "virtualNetwork_peering_local": { "copy": { "name": "virtualNetwork_peering_local", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -3127,15 +3447,27 @@ "localVnetName": { "value": "[parameters('name')]" }, - "remoteVirtualNetworkId": { - "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + "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')]" }, - "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()))]" + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -3143,8 +3475,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3153,9 +3485,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -3164,7 +3496,7 @@ "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": { + "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." @@ -3209,7 +3541,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -3218,7 +3550,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -3255,14 +3587,14 @@ "virtualNetwork_peering_remote": { "copy": { "name": "virtualNetwork_peering_remote", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, - "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", + "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(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", - "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -3270,17 +3602,29 @@ "mode": "Incremental", "parameters": { "localVnetName": { - "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "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()))]" + "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#", @@ -3288,8 +3632,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3298,9 +3642,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -3309,7 +3653,7 @@ "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": { + "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." @@ -3354,7 +3698,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -3363,7 +3707,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -3426,8 +3770,8 @@ "description": "The names of the deployed subnets." }, "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[parameters('subnets')[copyIndex()].name]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" } }, "subnetResourceIds": { @@ -3436,8 +3780,8 @@ "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)]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" } }, "location": { @@ -3445,7 +3789,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('virtualNetwork', '2023-11-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" } } } @@ -3487,8 +3831,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3320668363507906643" + "version": "0.30.23.60470", + "templateHash": "15250207882926040999" } }, "parameters": { @@ -13299,28 +13643,7 @@ "[parameters('virtualNetworkDeploymentScriptAddressPrefix')]" ] }, - "subnets": { - "value": [ - { - "addressPrefix": "[if(not(empty(parameters('resourceProviders'))), cidrSubnet(parameters('virtualNetworkDeploymentScriptAddressPrefix'), 24, 0), null())]", - "name": "ds-subnet-001", - "networkSecurityGroupResourceId": "[if(not(empty(parameters('resourceProviders'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('deploymentScriptResourceGroupName')), 'Microsoft.Resources/deployments', variables('deploymentNames').createDsNsg), '2022-09-01').outputs.resourceId.value, null())]", - "serviceEndpoints": [ - { - "service": "Microsoft.Storage" - } - ], - "delegations": [ - { - "name": "Microsoft.ContainerInstance.containerGroups", - "properties": { - "serviceName": "Microsoft.ContainerInstance/containerGroups" - } - } - ] - } - ] - }, + "subnets": "[if(not(empty(parameters('resourceProviders'))), createObject('value', createArray(createObject('addressPrefix', if(not(empty(parameters('resourceProviders'))), cidrSubnet(parameters('virtualNetworkDeploymentScriptAddressPrefix'), 24, 0), null()), 'name', 'ds-subnet-001', 'networkSecurityGroupResourceId', if(not(empty(parameters('resourceProviders'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('deploymentScriptResourceGroupName')), 'Microsoft.Resources/deployments', variables('deploymentNames').createDsNsg), '2022-09-01').outputs.resourceId.value, null()), 'serviceEndpoints', createArray('Microsoft.Storage'), 'delegation', 'Microsoft.ContainerInstance/containerGroups'))), createObject('value', null()))]", "enableTelemetry": { "value": "[parameters('enableTelemetry')]" } @@ -13332,8 +13655,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16637670595978489426" + "version": "0.29.47.4906", + "templateHash": "15949466154563447171" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -13370,6 +13693,13 @@ "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": { @@ -13550,6 +13880,242 @@ } }, "nullable": true + }, + "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" + ], + "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": { + "$ref": "#/definitions/roleAssignmentType", + "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." + } + } + } } }, "parameters": { @@ -13572,32 +14138,48 @@ "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", - "defaultValue": [], + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, "metadata": { "description": "Optional. An Array of subnets to deploy to the Virtual Network." } }, "dnsServers": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { "description": "Optional. DNS Servers associated to the Virtual Network." } }, "ddosProtectionPlanResourceId": { "type": "string", - "defaultValue": "", + "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", - "defaultValue": [], + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, "metadata": { - "description": "Optional. Virtual Network Peerings configurations." + "description": "Optional. Virtual Network Peering configurations." } }, "vnetEncryption": { @@ -13657,15 +14239,29 @@ "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -13673,8 +14269,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.1.7', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -13692,42 +14288,21 @@ }, "virtualNetwork": { "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-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')]" }, + "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())]" + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" } }, "virtualNetwork_lock": { @@ -13788,20 +14363,20 @@ "virtualNetwork_roleAssignments": { "copy": { "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -13810,7 +14385,7 @@ "virtualNetwork_subnets": { "copy": { "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", "mode": "serial", "batchSize": 1 }, @@ -13827,23 +14402,50 @@ "value": "[parameters('name')]" }, "name": { - "value": "[parameters('subnets')[copyIndex()].name]" + "value": "[coalesce(parameters('subnets'), createArray())[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()))]" + "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#", @@ -13852,8 +14454,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "9634407864982934565" + "version": "0.29.47.4906", + "templateHash": "5699372618313647761" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -13865,6 +14467,13 @@ "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": { @@ -13931,7 +14540,7 @@ "name": { "type": "string", "metadata": { - "description": "Optional. The Name of the subnet resource." + "description": "Requird. The Name of the subnet resource." } }, "virtualNetworkName": { @@ -13942,41 +14551,45 @@ }, "addressPrefix": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The address prefix for the subnet." + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." } }, "networkSecurityGroupResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the network security group to assign to the subnet." } }, "routeTableResourceId": { "type": "string", - "defaultValue": "", + "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." } }, - "delegations": { - "type": "array", - "defaultValue": [], + "delegation": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. The delegations to enable on the subnet." + "description": "Optional. The delegation to enable on the subnet." } }, "natGatewayResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." } @@ -13990,7 +14603,7 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." } }, "privateLinkServiceNetworkPolicies": { @@ -14002,28 +14615,42 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." } }, "addressPrefixes": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. List of address prefixes for the subnet." + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." } }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "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." } }, - "ipAllocations": { + "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. Array of IpAllocation which reference this subnet." + "description": "Optional. Application gateway IP configurations of virtual network resource." } }, "serviceEndpointPolicies": { @@ -14041,12 +14668,19 @@ } }, "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')]", + "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')]" } }, @@ -14054,26 +14688,35 @@ "virtualNetwork": { "existing": true, "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[parameters('virtualNetworkName')]" }, "subnet": { "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2023-11-01", + "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())]", - "serviceEndpoints": "[parameters('serviceEndpoints')]", - "delegations": "[parameters('delegations')]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", "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')]" + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" }, "dependsOn": [ "virtualNetwork" @@ -14082,20 +14725,20 @@ "subnet_roleAssignments": { "copy": { "name": "subnet_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "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": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -14124,19 +14767,19 @@ }, "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" }, - "subnetAddressPrefix": { + "addressPrefix": { "type": "string", "metadata": { "description": "The address prefix for the subnet." }, - "value": "[reference('subnet').addressPrefix]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" }, - "subnetAddressPrefixes": { + "addressPrefixes": { "type": "array", "metadata": { "description": "List of address prefixes for the subnet." }, - "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" } } } @@ -14148,7 +14791,7 @@ "virtualNetwork_peering_local": { "copy": { "name": "virtualNetwork_peering_local", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -14162,15 +14805,27 @@ "localVnetName": { "value": "[parameters('name')]" }, - "remoteVirtualNetworkId": { - "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + "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')]" }, - "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()))]" + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -14178,8 +14833,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -14188,9 +14843,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -14199,7 +14854,7 @@ "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": { + "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." @@ -14244,7 +14899,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -14253,7 +14908,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -14290,14 +14945,14 @@ "virtualNetwork_peering_remote": { "copy": { "name": "virtualNetwork_peering_remote", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, - "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", + "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(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", - "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -14305,17 +14960,29 @@ "mode": "Incremental", "parameters": { "localVnetName": { - "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "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()))]" + "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#", @@ -14323,8 +14990,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -14333,9 +15000,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -14344,7 +15011,7 @@ "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": { + "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." @@ -14389,7 +15056,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -14398,7 +15065,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -14461,8 +15128,8 @@ "description": "The names of the deployed subnets." }, "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[parameters('subnets')[copyIndex()].name]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" } }, "subnetResourceIds": { @@ -14471,8 +15138,8 @@ "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)]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" } }, "location": { @@ -14480,7 +15147,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('virtualNetwork', '2023-11-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" } } } diff --git a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep index bd8fddf190..ab9684a5a6 100644 --- a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep +++ b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep @@ -361,7 +361,7 @@ module tagResourceGroup 'tags.bicep' = if (virtualNetworkEnabled && !empty(virtu } } -module createLzVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (virtualNetworkEnabled && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) { +module createLzVnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (virtualNetworkEnabled && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) { dependsOn: [ createResourceGroupForLzNetworking ] @@ -377,19 +377,19 @@ module createLzVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (virt peerings: (virtualNetworkEnabled && virtualNetworkPeeringEnabled && !empty(hubVirtualNetworkResourceIdChecked) && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) ? [ { + remoteVirtualNetworkResourceId: hubVirtualNetworkResourceIdChecked allowForwardedTraffic: true allowVirtualNetworkAccess: true allowGatewayTransit: false useRemoteGateways: virtualNetworkUseRemoteGateways remotePeeringEnabled: virtualNetworkPeeringEnabled - remoteVirtualNetworkId: hubVirtualNetworkResourceIdChecked remotePeeringAllowForwardedTraffic: true remotePeeringAllowVirtualNetworkAccess: true remotePeeringAllowGatewayTransit: true remotePeeringUseRemoteGateways: false } ] - : [] + : null enableTelemetry: enableTelemetry } } @@ -552,7 +552,7 @@ module createDsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' } } -module createDsVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (!empty(resourceProviders)) { +module createDsVnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (!empty(resourceProviders)) { scope: resourceGroup(subscriptionId, deploymentScriptResourceGroupName) name: deploymentNames.createdsVnet params: { @@ -561,26 +561,21 @@ module createDsVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (!emp addressPrefixes: [ virtualNetworkDeploymentScriptAddressPrefix ] - subnets: [ - { - addressPrefix: !empty(resourceProviders) ? cidrSubnet(virtualNetworkDeploymentScriptAddressPrefix, 24, 0) : null - name: 'ds-subnet-001' - networkSecurityGroupResourceId: !empty(resourceProviders) ? createDsNsg.outputs.resourceId : null - serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } - ] - delegations: [ + subnets: !empty(resourceProviders) + ? [ { - name: 'Microsoft.ContainerInstance.containerGroups' - properties: { - serviceName: 'Microsoft.ContainerInstance/containerGroups' - } + addressPrefix: !empty(resourceProviders) + ? cidrSubnet(virtualNetworkDeploymentScriptAddressPrefix, 24, 0) + : null + name: 'ds-subnet-001' + networkSecurityGroupResourceId: !empty(resourceProviders) ? createDsNsg.outputs.resourceId : null + serviceEndpoints: [ + 'Microsoft.Storage' + ] + delegation: 'Microsoft.ContainerInstance/containerGroups' } ] - } - ] + : null enableTelemetry: enableTelemetry } } From 2a435324edf8b63919af3c97b20eea38f14ef218 Mon Sep 17 00:00:00 2001 From: Tony Box Date: Mon, 30 Sep 2024 14:35:24 -0700 Subject: [PATCH 24/93] fix: add displayName to more submodules (#3342) ## Description Fixes #3328 - Add option to set displayName for authorizationserver, product, subscription resources ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.api-management.service](https://github.com/tony-box/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml/badge.svg?branch=feat%2Fapim_apiupdate)](https://github.com/tony-box/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Tony Box --- avm/res/api-management/service/README.md | 12 ++ .../service/api-version-set/main.json | 4 +- .../service/api/diagnostics/main.json | 4 +- avm/res/api-management/service/api/main.json | 12 +- .../service/api/policy/main.json | 4 +- .../service/authorization-server/README.md | 8 ++ .../service/authorization-server/main.bicep | 6 +- .../service/authorization-server/main.json | 13 ++- .../api-management/service/backend/main.json | 4 +- .../api-management/service/cache/main.json | 4 +- .../service/identity-provider/main.json | 4 +- .../api-management/service/loggers/main.json | 4 +- avm/res/api-management/service/main.bicep | 3 + avm/res/api-management/service/main.json | 108 +++++++++++------- .../service/named-value/main.json | 4 +- .../api-management/service/policy/main.json | 4 +- .../service/portalsetting/main.json | 4 +- .../api-management/service/product/README.md | 8 ++ .../service/product/api/main.json | 4 +- .../service/product/group/main.json | 4 +- .../api-management/service/product/main.bicep | 6 +- .../api-management/service/product/main.json | 21 ++-- .../service/subscription/README.md | 8 ++ .../service/subscription/main.bicep | 6 +- .../service/subscription/main.json | 13 ++- .../service/tests/e2e/max/main.test.bicep | 3 + .../tests/e2e/waf-aligned/main.test.bicep | 2 + avm/res/api-management/service/version.json | 4 +- 28 files changed, 194 insertions(+), 87 deletions(-) diff --git a/avm/res/api-management/service/README.md b/avm/res/api-management/service/README.md index c219b2de19..b95709dc50 100644 --- a/avm/res/api-management/service/README.md +++ b/avm/res/api-management/service/README.md @@ -290,6 +290,7 @@ module service 'br/public:avm/res/api-management/service:' = { clientId: 'apimclientid' clientRegistrationEndpoint: 'http://localhost' clientSecret: '' + displayName: 'AuthServer1' grantTypes: [ 'authorizationCode' ] @@ -404,6 +405,7 @@ module service 'br/public:avm/res/api-management/service:' = { } ] approvalRequired: false + displayName: 'Starter' groups: [ { name: 'developers' @@ -436,6 +438,7 @@ module service 'br/public:avm/res/api-management/service:' = { subnetResourceId: '' subscriptions: [ { + displayName: 'testArmSubscriptionAllApis' name: 'testArmSubscriptionAllApis' scope: '/apis' } @@ -525,6 +528,7 @@ module service 'br/public:avm/res/api-management/service:' = { "clientId": "apimclientid", "clientRegistrationEndpoint": "http://localhost", "clientSecret": "", + "displayName": "AuthServer1", "grantTypes": [ "authorizationCode" ], @@ -663,6 +667,7 @@ module service 'br/public:avm/res/api-management/service:' = { } ], "approvalRequired": false, + "displayName": "Starter", "groups": [ { "name": "developers" @@ -703,6 +708,7 @@ module service 'br/public:avm/res/api-management/service:' = { "subscriptions": { "value": [ { + "displayName": "testArmSubscriptionAllApis", "name": "testArmSubscriptionAllApis", "scope": "/apis" } @@ -837,6 +843,7 @@ module service 'br/public:avm/res/api-management/service:' = { clientId: 'apimClientid' clientRegistrationEndpoint: 'https://localhost' clientSecret: '' + displayName: 'AuthServer1' grantTypes: [ 'authorizationCode' ] @@ -973,6 +980,7 @@ module service 'br/public:avm/res/api-management/service:' = { ] subscriptions: [ { + displayName: 'testArmSubscriptionAllApis' name: 'testArmSubscriptionAllApis' scope: '/apis' } @@ -1048,6 +1056,7 @@ module service 'br/public:avm/res/api-management/service:' = { "clientId": "apimClientid", "clientRegistrationEndpoint": "https://localhost", "clientSecret": "", + "displayName": "AuthServer1", "grantTypes": [ "authorizationCode" ], @@ -1212,6 +1221,7 @@ module service 'br/public:avm/res/api-management/service:' = { "subscriptions": { "value": [ { + "displayName": "testArmSubscriptionAllApis", "name": "testArmSubscriptionAllApis", "scope": "/apis" } @@ -1927,6 +1937,8 @@ A list of availability zones denoting where the resource needs to come from. Onl ## Notes +The latest version of this module only includes supported versions of the API Management resource. All unsupported versions of API Management have been removed from the related parameters. See the [API Management stv1 platform retirement](!https://learn.microsoft.com/en-us/azure/api-management/breaking-changes/stv1-platform-retirement-august-2024) article for more details. + ### Parameter Usage: `apiManagementServicePolicy`
diff --git a/avm/res/api-management/service/api-version-set/main.json b/avm/res/api-management/service/api-version-set/main.json index 85639acf5c..061641030c 100644 --- a/avm/res/api-management/service/api-version-set/main.json +++ b/avm/res/api-management/service/api-version-set/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17159723717884761443" + "version": "0.30.23.60470", + "templateHash": "2492486199367242598" }, "name": "API Management Service API Version Sets", "description": "This module deploys an API Management Service API Version Set.", diff --git a/avm/res/api-management/service/api/diagnostics/main.json b/avm/res/api-management/service/api/diagnostics/main.json index 83e2b3a003..6db7e0f400 100644 --- a/avm/res/api-management/service/api/diagnostics/main.json +++ b/avm/res/api-management/service/api/diagnostics/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", diff --git a/avm/res/api-management/service/api/main.json b/avm/res/api-management/service/api/main.json index 970b83350d..a87b3409db 100644 --- a/avm/res/api-management/service/api/main.json +++ b/avm/res/api-management/service/api/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17160750790361326516" + "version": "0.30.23.60470", + "templateHash": "17036957862982683599" }, "name": "API Management Service APIs", "description": "This module deploys an API Management Service API.", @@ -283,8 +283,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2474188503939052987" + "version": "0.30.23.60470", + "templateHash": "5643177447182050438" }, "name": "API Management Service APIs Policies", "description": "This module deploys an API Management Service API Policy.", @@ -430,8 +430,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", diff --git a/avm/res/api-management/service/api/policy/main.json b/avm/res/api-management/service/api/policy/main.json index 6defcce4a3..af5ae11307 100644 --- a/avm/res/api-management/service/api/policy/main.json +++ b/avm/res/api-management/service/api/policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2474188503939052987" + "version": "0.30.23.60470", + "templateHash": "5643177447182050438" }, "name": "API Management Service APIs Policies", "description": "This module deploys an API Management Service API Policy.", diff --git a/avm/res/api-management/service/authorization-server/README.md b/avm/res/api-management/service/authorization-server/README.md index d6996e57a1..234576e93d 100644 --- a/avm/res/api-management/service/authorization-server/README.md +++ b/avm/res/api-management/service/authorization-server/README.md @@ -23,6 +23,7 @@ This module deploys an API Management Service Authorization Server. | [`authorizationEndpoint`](#parameter-authorizationendpoint) | string | OAuth authorization endpoint. See . | | [`clientId`](#parameter-clientid) | securestring | Client or app ID registered with this authorization server. | | [`clientSecret`](#parameter-clientsecret) | securestring | Client or app secret registered with this authorization server. This property will not be filled on 'GET' operations! Use '/listSecrets' POST request to get the value. | +| [`displayName`](#parameter-displayname) | string | API Management Service Authorization Servers name. Must be 1 to 50 characters long. | | [`grantTypes`](#parameter-granttypes) | array | Form of an authorization grant, which the client uses to request the access token. - authorizationCode, implicit, resourceOwnerPassword, clientCredentials. | | [`name`](#parameter-name) | string | Identifier of the authorization server. | @@ -69,6 +70,13 @@ Client or app secret registered with this authorization server. This property wi - Required: Yes - Type: securestring +### Parameter: `displayName` + +API Management Service Authorization Servers name. Must be 1 to 50 characters long. + +- Required: Yes +- Type: string + ### Parameter: `grantTypes` Form of an authorization grant, which the client uses to request the access token. - authorizationCode, implicit, resourceOwnerPassword, clientCredentials. diff --git a/avm/res/api-management/service/authorization-server/main.bicep b/avm/res/api-management/service/authorization-server/main.bicep index 3be6ae0b89..afe57ae5cd 100644 --- a/avm/res/api-management/service/authorization-server/main.bicep +++ b/avm/res/api-management/service/authorization-server/main.bicep @@ -5,6 +5,10 @@ metadata owner = 'Azure/module-maintainers' @description('Required. Identifier of the authorization server.') param name string +@description('Required. API Management Service Authorization Servers name. Must be 1 to 50 characters long.') +@maxLength(50) +param displayName string + @description('Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment.') param apiManagementServiceName string @@ -85,7 +89,7 @@ resource authorizationServer 'Microsoft.ApiManagement/service/authorizationServe bearerTokenSendingMethods: bearerTokenSendingMethods resourceOwnerUsername: resourceOwnerUsername resourceOwnerPassword: resourceOwnerPassword - displayName: name + displayName: displayName clientRegistrationEndpoint: clientRegistrationEndpoint authorizationEndpoint: authorizationEndpoint grantTypes: grantTypes diff --git a/avm/res/api-management/service/authorization-server/main.json b/avm/res/api-management/service/authorization-server/main.json index e966a03d7f..50d0897a93 100644 --- a/avm/res/api-management/service/authorization-server/main.json +++ b/avm/res/api-management/service/authorization-server/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4256977187793378377" + "version": "0.30.23.60470", + "templateHash": "17927787726774417819" }, "name": "API Management Service Authorization Servers", "description": "This module deploys an API Management Service Authorization Server.", @@ -18,6 +18,13 @@ "description": "Required. Identifier of the authorization server." } }, + "displayName": { + "type": "string", + "maxLength": 50, + "metadata": { + "description": "Required. API Management Service Authorization Servers name. Must be 1 to 50 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -154,7 +161,7 @@ "bearerTokenSendingMethods": "[parameters('bearerTokenSendingMethods')]", "resourceOwnerUsername": "[parameters('resourceOwnerUsername')]", "resourceOwnerPassword": "[parameters('resourceOwnerPassword')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "clientRegistrationEndpoint": "[parameters('clientRegistrationEndpoint')]", "authorizationEndpoint": "[parameters('authorizationEndpoint')]", "grantTypes": "[parameters('grantTypes')]", diff --git a/avm/res/api-management/service/backend/main.json b/avm/res/api-management/service/backend/main.json index 2a5ea70d52..c3ae5f49b2 100644 --- a/avm/res/api-management/service/backend/main.json +++ b/avm/res/api-management/service/backend/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2365531440872951056" + "version": "0.30.23.60470", + "templateHash": "14706757128951530017" }, "name": "API Management Service Backends", "description": "This module deploys an API Management Service Backend.", diff --git a/avm/res/api-management/service/cache/main.json b/avm/res/api-management/service/cache/main.json index b66a377833..285f53b0fb 100644 --- a/avm/res/api-management/service/cache/main.json +++ b/avm/res/api-management/service/cache/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3234729148013684780" + "version": "0.30.23.60470", + "templateHash": "2750555671183513052" }, "name": "API Management Service Caches", "description": "This module deploys an API Management Service Cache.", diff --git a/avm/res/api-management/service/identity-provider/main.json b/avm/res/api-management/service/identity-provider/main.json index f9e6cbe086..6768ba8a3e 100644 --- a/avm/res/api-management/service/identity-provider/main.json +++ b/avm/res/api-management/service/identity-provider/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12757169124799431378" + "version": "0.30.23.60470", + "templateHash": "1342690797398622979" }, "name": "API Management Service Identity Providers", "description": "This module deploys an API Management Service Identity Provider.", diff --git a/avm/res/api-management/service/loggers/main.json b/avm/res/api-management/service/loggers/main.json index 9a6b6378bd..7d3305a3cd 100644 --- a/avm/res/api-management/service/loggers/main.json +++ b/avm/res/api-management/service/loggers/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12986610229102962453" + "version": "0.30.23.60470", + "templateHash": "12834599511984803283" }, "name": "API Management Service Loggers", "description": "This module deploys an API Management Service Logger.", diff --git a/avm/res/api-management/service/main.bicep b/avm/res/api-management/service/main.bicep index 1e69199417..37a49b86c0 100644 --- a/avm/res/api-management/service/main.bicep +++ b/avm/res/api-management/service/main.bicep @@ -310,6 +310,7 @@ module service_authorizationServers 'authorization-server/main.bicep' = [ params: { apiManagementServiceName: service.name name: authorizationServer.name + displayName: authorizationServer.displayName authorizationEndpoint: authorizationServer.authorizationEndpoint authorizationMethods: authorizationServer.?authorizationMethods ?? ['GET'] bearerTokenSendingMethods: authorizationServer.?bearerTokenSendingMethods ?? ['authorizationHeader'] @@ -467,6 +468,7 @@ module service_products 'product/main.bicep' = [ for (product, index) in products: { name: '${uniqueString(deployment().name, location)}-Apim-Product-${index}' params: { + displayName: product.displayName apiManagementServiceName: service.name apis: product.?apis ?? [] approvalRequired: product.?approvalRequired ?? false @@ -490,6 +492,7 @@ module service_subscriptions 'subscription/main.bicep' = [ params: { apiManagementServiceName: service.name name: subscription.name + displayName: subscription.displayName allowTracing: subscription.?allowTracing ownerId: subscription.?ownerId primaryKey: subscription.?primaryKey diff --git a/avm/res/api-management/service/main.json b/avm/res/api-management/service/main.json index 64675ab023..fc42a71966 100644 --- a/avm/res/api-management/service/main.json +++ b/avm/res/api-management/service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5150103142771299599" + "version": "0.30.23.60470", + "templateHash": "7676062632439815762" }, "name": "API Management Services", "description": "This module deploys an API Management Service. The default deployment is set to use a Premium SKU to align with Microsoft WAF-aligned best practices. In most cases, non-prod deployments should use a lower-tier SKU.", @@ -791,8 +791,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17160750790361326516" + "version": "0.30.23.60470", + "templateHash": "17036957862982683599" }, "name": "API Management Service APIs", "description": "This module deploys an API Management Service API.", @@ -1069,8 +1069,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2474188503939052987" + "version": "0.30.23.60470", + "templateHash": "5643177447182050438" }, "name": "API Management Service APIs Policies", "description": "This module deploys an API Management Service API Policy.", @@ -1216,8 +1216,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", @@ -1444,8 +1444,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17159723717884761443" + "version": "0.30.23.60470", + "templateHash": "2492486199367242598" }, "name": "API Management Service API Version Sets", "description": "This module deploys an API Management Service API Version Set.", @@ -1530,6 +1530,9 @@ "name": { "value": "[variables('authorizationServerList')[copyIndex()].name]" }, + "displayName": { + "value": "[variables('authorizationServerList')[copyIndex()].displayName]" + }, "authorizationEndpoint": { "value": "[variables('authorizationServerList')[copyIndex()].authorizationEndpoint]" }, @@ -1582,8 +1585,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4256977187793378377" + "version": "0.30.23.60470", + "templateHash": "17927787726774417819" }, "name": "API Management Service Authorization Servers", "description": "This module deploys an API Management Service Authorization Server.", @@ -1596,6 +1599,13 @@ "description": "Required. Identifier of the authorization server." } }, + "displayName": { + "type": "string", + "maxLength": 50, + "metadata": { + "description": "Required. API Management Service Authorization Servers name. Must be 1 to 50 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -1732,7 +1742,7 @@ "bearerTokenSendingMethods": "[parameters('bearerTokenSendingMethods')]", "resourceOwnerUsername": "[parameters('resourceOwnerUsername')]", "resourceOwnerPassword": "[parameters('resourceOwnerPassword')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "clientRegistrationEndpoint": "[parameters('clientRegistrationEndpoint')]", "authorizationEndpoint": "[parameters('authorizationEndpoint')]", "grantTypes": "[parameters('grantTypes')]", @@ -1825,8 +1835,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2365531440872951056" + "version": "0.30.23.60470", + "templateHash": "14706757128951530017" }, "name": "API Management Service Backends", "description": "This module deploys an API Management Service Backend.", @@ -2009,8 +2019,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3234729148013684780" + "version": "0.30.23.60470", + "templateHash": "2750555671183513052" }, "name": "API Management Service Caches", "description": "This module deploys an API Management Service Cache.", @@ -2167,8 +2177,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", @@ -2397,8 +2407,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12757169124799431378" + "version": "0.30.23.60470", + "templateHash": "1342690797398622979" }, "name": "API Management Service Identity Providers", "description": "This module deploys an API Management Service Identity Provider.", @@ -2610,8 +2620,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12986610229102962453" + "version": "0.30.23.60470", + "templateHash": "12834599511984803283" }, "name": "API Management Service Loggers", "description": "This module deploys an API Management Service Logger.", @@ -2754,8 +2764,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3479776319506170502" + "version": "0.30.23.60470", + "templateHash": "10162843567606353040" }, "name": "API Management Service Named Values", "description": "This module deploys an API Management Service Named Value.", @@ -2895,8 +2905,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10271256088614129674" + "version": "0.30.23.60470", + "templateHash": "14869704072680236257" }, "name": "API Management Service Portal Settings", "description": "This module deploys an API Management Service Portal Setting.", @@ -2994,8 +3004,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11443463088593763324" + "version": "0.30.23.60470", + "templateHash": "9395795206748286282" }, "name": "API Management Service Policies", "description": "This module deploys an API Management Service Policy.", @@ -3089,6 +3099,9 @@ }, "mode": "Incremental", "parameters": { + "displayName": { + "value": "[parameters('products')[copyIndex()].displayName]" + }, "apiManagementServiceName": { "value": "[parameters('name')]" }, @@ -3126,8 +3139,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6230115773857876317" + "version": "0.30.23.60470", + "templateHash": "8029364311033748838" }, "name": "API Management Service Products", "description": "This module deploys an API Management Service Product.", @@ -3140,6 +3153,13 @@ "description": "Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment." } }, + "displayName": { + "type": "string", + "maxLength": 300, + "metadata": { + "description": "Required. API Management Service Products name. Must be 1 to 300 characters long." + } + }, "approvalRequired": { "type": "bool", "defaultValue": false, @@ -3210,7 +3230,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "description": "[parameters('description')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "terms": "[parameters('terms')]", "subscriptionRequired": "[parameters('subscriptionRequired')]", "approvalRequired": "[if(parameters('subscriptionRequired'), parameters('approvalRequired'), null())]", @@ -3248,8 +3268,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1052981479169082206" + "version": "0.30.23.60470", + "templateHash": "602104798329438871" }, "name": "API Management Service Products APIs", "description": "This module deploys an API Management Service Product API.", @@ -3338,8 +3358,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5748451278124986706" + "version": "0.30.23.60470", + "templateHash": "5238408376918932137" }, "name": "API Management Service Products Groups", "description": "This module deploys an API Management Service Product Group.", @@ -3469,6 +3489,9 @@ "name": { "value": "[parameters('subscriptions')[copyIndex()].name]" }, + "displayName": { + "value": "[parameters('subscriptions')[copyIndex()].displayName]" + }, "allowTracing": { "value": "[tryGet(parameters('subscriptions')[copyIndex()], 'allowTracing')]" }, @@ -3495,8 +3518,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9499976066778278010" + "version": "0.30.23.60470", + "templateHash": "16082435269276611452" }, "name": "API Management Service Subscriptions", "description": "This module deploys an API Management Service Subscription.", @@ -3510,6 +3533,13 @@ "description": "Optional. Determines whether tracing can be enabled." } }, + "displayName": { + "type": "string", + "maxLength": 100, + "metadata": { + "description": "Required. API Management Service Subscriptions name. Must be 1 to 100 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -3571,7 +3601,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "scope": "[parameters('scope')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "ownerId": "[parameters('ownerId')]", "primaryKey": "[parameters('primaryKey')]", "secondaryKey": "[parameters('secondaryKey')]", diff --git a/avm/res/api-management/service/named-value/main.json b/avm/res/api-management/service/named-value/main.json index 4be9cba518..b182535671 100644 --- a/avm/res/api-management/service/named-value/main.json +++ b/avm/res/api-management/service/named-value/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3479776319506170502" + "version": "0.30.23.60470", + "templateHash": "10162843567606353040" }, "name": "API Management Service Named Values", "description": "This module deploys an API Management Service Named Value.", diff --git a/avm/res/api-management/service/policy/main.json b/avm/res/api-management/service/policy/main.json index 83d9434240..dd3c7eab82 100644 --- a/avm/res/api-management/service/policy/main.json +++ b/avm/res/api-management/service/policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11443463088593763324" + "version": "0.30.23.60470", + "templateHash": "9395795206748286282" }, "name": "API Management Service Policies", "description": "This module deploys an API Management Service Policy.", diff --git a/avm/res/api-management/service/portalsetting/main.json b/avm/res/api-management/service/portalsetting/main.json index 779c574120..d68c8ed791 100644 --- a/avm/res/api-management/service/portalsetting/main.json +++ b/avm/res/api-management/service/portalsetting/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10271256088614129674" + "version": "0.30.23.60470", + "templateHash": "14869704072680236257" }, "name": "API Management Service Portal Settings", "description": "This module deploys an API Management Service Portal Setting.", diff --git a/avm/res/api-management/service/product/README.md b/avm/res/api-management/service/product/README.md index c5b8331a4a..9dbc604abb 100644 --- a/avm/res/api-management/service/product/README.md +++ b/avm/res/api-management/service/product/README.md @@ -22,6 +22,7 @@ This module deploys an API Management Service Product. | Parameter | Type | Description | | :-- | :-- | :-- | +| [`displayName`](#parameter-displayname) | string | API Management Service Products name. Must be 1 to 300 characters long. | | [`name`](#parameter-name) | string | Product Name. | **Conditional parameters** @@ -43,6 +44,13 @@ This module deploys an API Management Service Product. | [`subscriptionsLimit`](#parameter-subscriptionslimit) | int | Whether the number of subscriptions a user can have to this product at the same time. Set to null or omit to allow unlimited per user subscriptions. Can be present only if subscriptionRequired property is present and has a value of false. | | [`terms`](#parameter-terms) | string | Product terms of use. Developers trying to subscribe to the product will be presented and required to accept these terms before they can complete the subscription process. | +### Parameter: `displayName` + +API Management Service Products name. Must be 1 to 300 characters long. + +- Required: Yes +- Type: string + ### Parameter: `name` Product Name. diff --git a/avm/res/api-management/service/product/api/main.json b/avm/res/api-management/service/product/api/main.json index 4042b9bf61..5603f9f789 100644 --- a/avm/res/api-management/service/product/api/main.json +++ b/avm/res/api-management/service/product/api/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1052981479169082206" + "version": "0.30.23.60470", + "templateHash": "602104798329438871" }, "name": "API Management Service Products APIs", "description": "This module deploys an API Management Service Product API.", diff --git a/avm/res/api-management/service/product/group/main.json b/avm/res/api-management/service/product/group/main.json index 4ac13f0dac..28d5460152 100644 --- a/avm/res/api-management/service/product/group/main.json +++ b/avm/res/api-management/service/product/group/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5748451278124986706" + "version": "0.30.23.60470", + "templateHash": "5238408376918932137" }, "name": "API Management Service Products Groups", "description": "This module deploys an API Management Service Product Group.", diff --git a/avm/res/api-management/service/product/main.bicep b/avm/res/api-management/service/product/main.bicep index 9787974281..22ca0081c1 100644 --- a/avm/res/api-management/service/product/main.bicep +++ b/avm/res/api-management/service/product/main.bicep @@ -5,6 +5,10 @@ metadata owner = 'Azure/module-maintainers' @sys.description('Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment.') param apiManagementServiceName string +@sys.description('Required. API Management Service Products name. Must be 1 to 300 characters long.') +@maxLength(300) +param displayName string + @sys.description('Optional. Whether subscription approval is required. If false, new subscriptions will be approved automatically enabling developers to call the products APIs immediately after subscribing. If true, administrators must manually approve the subscription before the developer can any of the products APIs. Can be present only if subscriptionRequired property is present and has a value of false.') param approvalRequired bool = false @@ -41,7 +45,7 @@ resource product 'Microsoft.ApiManagement/service/products@2022-08-01' = { parent: service properties: { description: description - displayName: name + displayName: displayName terms: terms subscriptionRequired: subscriptionRequired approvalRequired: subscriptionRequired ? approvalRequired : null diff --git a/avm/res/api-management/service/product/main.json b/avm/res/api-management/service/product/main.json index 73dd3977b6..892a25de5c 100644 --- a/avm/res/api-management/service/product/main.json +++ b/avm/res/api-management/service/product/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6230115773857876317" + "version": "0.30.23.60470", + "templateHash": "8029364311033748838" }, "name": "API Management Service Products", "description": "This module deploys an API Management Service Product.", @@ -18,6 +18,13 @@ "description": "Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment." } }, + "displayName": { + "type": "string", + "maxLength": 300, + "metadata": { + "description": "Required. API Management Service Products name. Must be 1 to 300 characters long." + } + }, "approvalRequired": { "type": "bool", "defaultValue": false, @@ -88,7 +95,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "description": "[parameters('description')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "terms": "[parameters('terms')]", "subscriptionRequired": "[parameters('subscriptionRequired')]", "approvalRequired": "[if(parameters('subscriptionRequired'), parameters('approvalRequired'), null())]", @@ -126,8 +133,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1052981479169082206" + "version": "0.30.23.60470", + "templateHash": "602104798329438871" }, "name": "API Management Service Products APIs", "description": "This module deploys an API Management Service Product API.", @@ -216,8 +223,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5748451278124986706" + "version": "0.30.23.60470", + "templateHash": "5238408376918932137" }, "name": "API Management Service Products Groups", "description": "This module deploys an API Management Service Product Group.", diff --git a/avm/res/api-management/service/subscription/README.md b/avm/res/api-management/service/subscription/README.md index c851bed0dd..03e97821cd 100644 --- a/avm/res/api-management/service/subscription/README.md +++ b/avm/res/api-management/service/subscription/README.md @@ -20,6 +20,7 @@ This module deploys an API Management Service Subscription. | Parameter | Type | Description | | :-- | :-- | :-- | +| [`displayName`](#parameter-displayname) | string | API Management Service Subscriptions name. Must be 1 to 100 characters long. | | [`name`](#parameter-name) | string | Subscription name. | **Conditional parameters** @@ -39,6 +40,13 @@ This module deploys an API Management Service Subscription. | [`secondaryKey`](#parameter-secondarykey) | string | Secondary subscription key. If not specified during request key will be generated automatically. | | [`state`](#parameter-state) | string | Initial subscription state. If no value is specified, subscription is created with Submitted state. Possible states are "*" active "?" the subscription is active, "*" suspended "?" the subscription is blocked, and the subscriber cannot call any APIs of the product, * submitted ? the subscription request has been made by the developer, but has not yet been approved or rejected, * rejected ? the subscription request has been denied by an administrator, * cancelled ? the subscription has been cancelled by the developer or administrator, * expired ? the subscription reached its expiration date and was deactivated. - suspended, active, expired, submitted, rejected, cancelled. | +### Parameter: `displayName` + +API Management Service Subscriptions name. Must be 1 to 100 characters long. + +- Required: Yes +- Type: string + ### Parameter: `name` Subscription name. diff --git a/avm/res/api-management/service/subscription/main.bicep b/avm/res/api-management/service/subscription/main.bicep index 1b1e9411be..746242a7f9 100644 --- a/avm/res/api-management/service/subscription/main.bicep +++ b/avm/res/api-management/service/subscription/main.bicep @@ -5,6 +5,10 @@ metadata owner = 'Azure/module-maintainers' @description('Optional. Determines whether tracing can be enabled.') param allowTracing bool = true +@description('Required. API Management Service Subscriptions name. Must be 1 to 100 characters long.') +@maxLength(100) +param displayName string + @description('Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment.') param apiManagementServiceName string @@ -35,7 +39,7 @@ resource subscription 'Microsoft.ApiManagement/service/subscriptions@2022-08-01' parent: service properties: { scope: scope - displayName: name + displayName: displayName ownerId: ownerId primaryKey: primaryKey secondaryKey: secondaryKey diff --git a/avm/res/api-management/service/subscription/main.json b/avm/res/api-management/service/subscription/main.json index 5510d60858..6abc772cc3 100644 --- a/avm/res/api-management/service/subscription/main.json +++ b/avm/res/api-management/service/subscription/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9499976066778278010" + "version": "0.30.23.60470", + "templateHash": "16082435269276611452" }, "name": "API Management Service Subscriptions", "description": "This module deploys an API Management Service Subscription.", @@ -20,6 +20,13 @@ "description": "Optional. Determines whether tracing can be enabled." } }, + "displayName": { + "type": "string", + "maxLength": 100, + "metadata": { + "description": "Required. API Management Service Subscriptions name. Must be 1 to 100 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -81,7 +88,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "scope": "[parameters('scope')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "ownerId": "[parameters('ownerId')]", "primaryKey": "[parameters('primaryKey')]", "secondaryKey": "[parameters('secondaryKey')]", diff --git a/avm/res/api-management/service/tests/e2e/max/main.test.bicep b/avm/res/api-management/service/tests/e2e/max/main.test.bicep index 2989495645..e0419365c5 100644 --- a/avm/res/api-management/service/tests/e2e/max/main.test.bicep +++ b/avm/res/api-management/service/tests/e2e/max/main.test.bicep @@ -124,6 +124,7 @@ module testDeployment '../../../main.bicep' = [ 'authorizationCode' ] name: 'AuthServer1' + displayName: 'AuthServer1' tokenEndpoint: '${environment().authentication.loginEndpoint}651b43ce-ccb8-4301-b551-b04dd872d401/oauth2/v2.0/token' } ] @@ -241,6 +242,7 @@ module testDeployment '../../../main.bicep' = [ } ] name: 'Starter' + displayName: 'Starter' subscriptionRequired: false } ] @@ -270,6 +272,7 @@ module testDeployment '../../../main.bicep' = [ { name: 'testArmSubscriptionAllApis' scope: '/apis' + displayName: 'testArmSubscriptionAllApis' } ] managedIdentities: { diff --git a/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep b/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep index ccf1f295b4..b94ad37da7 100644 --- a/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep @@ -128,6 +128,7 @@ module testDeployment '../../../main.bicep' = [ 'authorizationCode' ] name: 'AuthServer1' + displayName: 'AuthServer1' tokenEndpoint: '${environment().authentication.loginEndpoint}651b43ce-ccb8-4301-b551-b04dd872d401/oauth2/v2.0/token' } ] @@ -243,6 +244,7 @@ module testDeployment '../../../main.bicep' = [ { name: 'testArmSubscriptionAllApis' scope: '/apis' + displayName: 'testArmSubscriptionAllApis' } ] tags: { diff --git a/avm/res/api-management/service/version.json b/avm/res/api-management/service/version.json index a8eda31021..9ed3662aba 100644 --- a/avm/res/api-management/service/version.json +++ b/avm/res/api-management/service/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.5", + "version": "0.6", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} From 3073a74cd75675d7c7ba5ddbcc2450f2482de7c6 Mon Sep 17 00:00:00 2001 From: Anders Eide Date: Tue, 1 Oct 2024 11:12:14 +0200 Subject: [PATCH 25/93] feat: Added cdn profile security policies support - `avm/res/cdn/profile` (#3025) ## Description Adds support for Security Policies on cdn/profile, making it possible to use the module to deploy Azure Front Door Premium with Web Application Firewall. Fixes #2376 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cdn.profile](https://github.com/anderseide/avm-bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg?branch=cdn-profile-security-policies)](https://github.com/anderseide/avm-bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Guillaume Beaud <79973892+gbeaud@users.noreply.github.com> --- avm/res/cdn/profile/README.md | 322 +++++++++++++++++- avm/res/cdn/profile/afdEndpoint/main.json | 8 +- .../cdn/profile/afdEndpoint/route/main.json | 4 +- avm/res/cdn/profile/customdomain/main.json | 4 +- avm/res/cdn/profile/endpoint/main.json | 8 +- avm/res/cdn/profile/endpoint/origin/main.json | 4 +- avm/res/cdn/profile/main.bicep | 31 ++ avm/res/cdn/profile/main.json | 278 +++++++++++++-- avm/res/cdn/profile/origingroup/main.json | 8 +- .../cdn/profile/origingroup/origin/main.json | 4 +- avm/res/cdn/profile/ruleset/main.json | 8 +- avm/res/cdn/profile/ruleset/rule/main.json | 4 +- avm/res/cdn/profile/secret/main.json | 4 +- .../cdn/profile/securityPolicies/README.md | 101 ++++++ .../cdn/profile/securityPolicies/main.bicep | 54 +++ .../cdn/profile/securityPolicies/main.json | 128 +++++++ .../tests/e2e/afd.premium/main.test.bicep | 146 ++++++++ avm/res/cdn/profile/version.json | 4 +- 18 files changed, 1060 insertions(+), 60 deletions(-) create mode 100644 avm/res/cdn/profile/securityPolicies/README.md create mode 100644 avm/res/cdn/profile/securityPolicies/main.bicep create mode 100644 avm/res/cdn/profile/securityPolicies/main.json create mode 100644 avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index 369cadf61b..e2de8fbea8 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -27,6 +27,7 @@ This module deploys a CDN Profile. | `Microsoft.Cdn/profiles/ruleSets` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2023-05-01/profiles/ruleSets) | | `Microsoft.Cdn/profiles/ruleSets/rules` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2023-05-01/profiles/ruleSets/rules) | | `Microsoft.Cdn/profiles/secrets` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2023-05-01/profiles/secrets) | +| `Microsoft.Cdn/profiles/securityPolicies` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/profiles/securityPolicies) | ## Usage examples @@ -36,12 +37,245 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/cdn/profile:`. -- [As Azure Front Door](#example-1-as-azure-front-door) -- [Using only defaults](#example-2-using-only-defaults) -- [Using large parameter set](#example-3-using-large-parameter-set) -- [WAF-aligned](#example-4-waf-aligned) +- [As Azure Front Door Premium](#example-1-as-azure-front-door-premium) +- [As Azure Front Door](#example-2-as-azure-front-door) +- [Using only defaults](#example-3-using-only-defaults) +- [Using large parameter set](#example-4-using-large-parameter-set) +- [WAF-aligned](#example-5-waf-aligned) -### Example 1: _As Azure Front Door_ +### Example 1: _As Azure Front Door Premium_ + +This instance deploys the module as Azure Front Door Premium. + + +
+ +via Bicep module + +```bicep +module profile 'br/public:avm/res/cdn/profile:' = { + name: 'profileDeployment' + params: { + // Required parameters + name: 'dep-test-cdnpafdp' + sku: 'Premium_AzureFrontDoor' + // Non-required parameters + afdEndpoints: [ + { + name: 'dep-test-cdnpafdp-afd-endpoint' + routes: [ + { + customDomainNames: [ + 'dep-test-cdnpafdp-custom-domain' + ] + name: 'dep-test-cdnpafdp-afd-route' + originGroupName: 'dep-test-cdnpafdp-origin-group' + ruleSets: [ + { + name: 'deptestcdnpafdpruleset' + } + ] + } + ] + } + ] + customDomains: [ + { + certificateType: 'ManagedCertificate' + hostName: 'dep-test-cdnpafdp-custom-domain.azurewebsites.net' + name: 'dep-test-cdnpafdp-custom-domain' + } + ] + location: 'global' + originGroups: [ + { + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + name: 'dep-test-cdnpafdp-origin-group' + origins: [ + { + hostName: 'dep-test-cdnpafdp-origin.azurewebsites.net' + name: 'dep-test-cdnpafdp-origin' + } + ] + } + ] + originResponseTimeoutSeconds: 60 + ruleSets: [ + { + name: 'deptestcdnpafdpruleset' + rules: [ + { + actions: [ + { + name: 'UrlRedirect' + parameters: { + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + customPath: '/test123' + destinationProtocol: 'Https' + redirectType: 'PermanentRedirect' + typeName: 'DeliveryRuleUrlRedirectActionParameters' + } + } + ] + name: 'deptestcdnpafdprule' + order: 1 + } + ] + } + ] + securityPolicies: [ + { + associations: [ + { + domains: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + } + ] + name: 'deptestcdnpafdpsecpol' + wafPolicyResourceId: '' + } + ] + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dep-test-cdnpafdp" + }, + "sku": { + "value": "Premium_AzureFrontDoor" + }, + // Non-required parameters + "afdEndpoints": { + "value": [ + { + "name": "dep-test-cdnpafdp-afd-endpoint", + "routes": [ + { + "customDomainNames": [ + "dep-test-cdnpafdp-custom-domain" + ], + "name": "dep-test-cdnpafdp-afd-route", + "originGroupName": "dep-test-cdnpafdp-origin-group", + "ruleSets": [ + { + "name": "deptestcdnpafdpruleset" + } + ] + } + ] + } + ] + }, + "customDomains": { + "value": [ + { + "certificateType": "ManagedCertificate", + "hostName": "dep-test-cdnpafdp-custom-domain.azurewebsites.net", + "name": "dep-test-cdnpafdp-custom-domain" + } + ] + }, + "location": { + "value": "global" + }, + "originGroups": { + "value": [ + { + "loadBalancingSettings": { + "additionalLatencyInMilliseconds": 50, + "sampleSize": 4, + "successfulSamplesRequired": 3 + }, + "name": "dep-test-cdnpafdp-origin-group", + "origins": [ + { + "hostName": "dep-test-cdnpafdp-origin.azurewebsites.net", + "name": "dep-test-cdnpafdp-origin" + } + ] + } + ] + }, + "originResponseTimeoutSeconds": { + "value": 60 + }, + "ruleSets": { + "value": [ + { + "name": "deptestcdnpafdpruleset", + "rules": [ + { + "actions": [ + { + "name": "UrlRedirect", + "parameters": { + "customHostname": "dev-etradefd.trade.azure.defra.cloud", + "customPath": "/test123", + "destinationProtocol": "Https", + "redirectType": "PermanentRedirect", + "typeName": "DeliveryRuleUrlRedirectActionParameters" + } + } + ], + "name": "deptestcdnpafdprule", + "order": 1 + } + ] + } + ] + }, + "securityPolicies": { + "value": [ + { + "associations": [ + { + "domains": [ + { + "id": "" + } + ], + "patternsToMatch": [ + "/*" + ] + } + ], + "name": "deptestcdnpafdpsecpol", + "wafPolicyResourceId": "" + } + ] + } + } +} +``` + +
+

+ +### Example 2: _As Azure Front Door_ This instance deploys the module as Azure Front Door. @@ -235,7 +469,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-### Example 2: _Using only defaults_ +### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -287,7 +521,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-### Example 3: _Using large parameter set_ +### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -455,7 +689,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-### Example 4: _WAF-aligned_ +### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -603,6 +837,7 @@ module profile 'br/public:avm/res/cdn/profile:' = { | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ruleSets`](#parameter-rulesets) | array | Array of rule set objects. | | [`secrets`](#parameter-secrets) | array | Array of secret objects. | +| [`securityPolicies`](#parameter-securitypolicies) | array | Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details). | | [`tags`](#parameter-tags) | object | Endpoint tags. | ### Parameter: `name` @@ -857,6 +1092,77 @@ Array of secret objects. - Type: array - Default: `[]` +### Parameter: `securityPolicies` + +Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details). + +- Required: No +- Type: array +- Default: `[]` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`associations`](#parameter-securitypoliciesassociations) | array | Domain names and URL patterns to math with this association. | +| [`name`](#parameter-securitypoliciesname) | string | Name of the security policy. | +| [`wafPolicyResourceId`](#parameter-securitypolicieswafpolicyresourceid) | string | Resource ID of WAF policy. | + +### Parameter: `securityPolicies.associations` + +Domain names and URL patterns to math with this association. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domains`](#parameter-securitypoliciesassociationsdomains) | array | List of domain resource id to associate with this resource. | +| [`patternsToMatch`](#parameter-securitypoliciesassociationspatternstomatch) | array | List of patterns to match with this association. | + +### Parameter: `securityPolicies.associations.domains` + +List of domain resource id to associate with this resource. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-securitypoliciesassociationsdomainsid) | string | ResourceID to domain that will be associated. | + +### Parameter: `securityPolicies.associations.domains.id` + +ResourceID to domain that will be associated. + +- Required: Yes +- Type: string + +### Parameter: `securityPolicies.associations.patternsToMatch` + +List of patterns to match with this association. + +- Required: Yes +- Type: array + +### Parameter: `securityPolicies.name` + +Name of the security policy. + +- Required: Yes +- Type: string + +### Parameter: `securityPolicies.wafPolicyResourceId` + +Resource ID of WAF policy. + +- Required: Yes +- Type: string + ### Parameter: `tags` Endpoint tags. diff --git a/avm/res/cdn/profile/afdEndpoint/main.json b/avm/res/cdn/profile/afdEndpoint/main.json index 1f55d5cd6e..7cfef24e3f 100644 --- a/avm/res/cdn/profile/afdEndpoint/main.json +++ b/avm/res/cdn/profile/afdEndpoint/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3384292547879688658" + "version": "0.30.23.60470", + "templateHash": "792735746278824384" }, "name": "CDN Profiles AFD Endpoints", "description": "This module deploys a CDN Profile AFD Endpoint.", @@ -156,8 +156,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18002678880456924020" + "version": "0.30.23.60470", + "templateHash": "1034122698174669197" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", diff --git a/avm/res/cdn/profile/afdEndpoint/route/main.json b/avm/res/cdn/profile/afdEndpoint/route/main.json index 6a415af662..852e97f10c 100644 --- a/avm/res/cdn/profile/afdEndpoint/route/main.json +++ b/avm/res/cdn/profile/afdEndpoint/route/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18002678880456924020" + "version": "0.30.23.60470", + "templateHash": "1034122698174669197" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", diff --git a/avm/res/cdn/profile/customdomain/main.json b/avm/res/cdn/profile/customdomain/main.json index dd0a43d181..e45727e4ad 100644 --- a/avm/res/cdn/profile/customdomain/main.json +++ b/avm/res/cdn/profile/customdomain/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15211066835326278081" + "version": "0.30.23.60470", + "templateHash": "16955838730426729961" }, "name": "CDN Profiles Custom Domains", "description": "This module deploys a CDN Profile Custom Domains.", diff --git a/avm/res/cdn/profile/endpoint/main.json b/avm/res/cdn/profile/endpoint/main.json index 2fa89e8711..273dbe9fce 100644 --- a/avm/res/cdn/profile/endpoint/main.json +++ b/avm/res/cdn/profile/endpoint/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6371656015674390162" + "version": "0.30.23.60470", + "templateHash": "3460565146034921053" }, "name": "CDN Profiles Endpoints", "description": "This module deploys a CDN Profile Endpoint.", @@ -125,8 +125,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11976988406992266750" + "version": "0.30.23.60470", + "templateHash": "4151069688274070352" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", diff --git a/avm/res/cdn/profile/endpoint/origin/main.json b/avm/res/cdn/profile/endpoint/origin/main.json index 13a2f8b35d..f4c079ff44 100644 --- a/avm/res/cdn/profile/endpoint/origin/main.json +++ b/avm/res/cdn/profile/endpoint/origin/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11976988406992266750" + "version": "0.30.23.60470", + "templateHash": "4151069688274070352" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", diff --git a/avm/res/cdn/profile/main.bicep b/avm/res/cdn/profile/main.bicep index c573133232..87323ba79f 100644 --- a/avm/res/cdn/profile/main.bicep +++ b/avm/res/cdn/profile/main.bicep @@ -49,6 +49,9 @@ param ruleSets array = [] @description('Optional. Array of AFD endpoint objects.') param afdEndpoints array = [] +@description('Optional. Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details).') +param securityPolicies securityPolicyType = [] + @description('Optional. Endpoint tags.') param tags object? @@ -251,6 +254,22 @@ module profile_afdEndpoints 'afdEndpoint/main.bicep' = [ } ] +module profile_securityPolicies 'securityPolicies/main.bicep' = [ + for (securityPolicy, index) in securityPolicies: { + name: '${uniqueString(deployment().name)}-Profile-SecurityPolicy-${index}' + dependsOn: [ + profile_afdEndpoints + profile_customDomains + ] + params: { + name: securityPolicy.name + profileName: profile.name + associations: securityPolicy.associations + wafPolicyResourceId: securityPolicy.wafPolicyResourceId + } + } +] + @description('The name of the CDN profile.') output name string = profile.name @@ -279,6 +298,18 @@ output uri string = !empty(endpointProperties) ? profile_endpoint.outputs.uri : // Definitions // // =============== // +import { associationsType } from 'securityPolicies/main.bicep' +type securityPolicyType = { + @description('Required. Name of the security policy.') + name: string + + @description('Required. Domain names and URL patterns to math with this association.') + associations: associationsType + + @description('Required. Resource ID of WAF policy.') + wafPolicyResourceId: string +}[] + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/avm/res/cdn/profile/main.json b/avm/res/cdn/profile/main.json index 965bf9cb4c..169cee8564 100644 --- a/avm/res/cdn/profile/main.json +++ b/avm/res/cdn/profile/main.json @@ -5,14 +5,40 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16789354290120442948" + "version": "0.30.23.60470", + "templateHash": "18013902785904421717" }, "name": "CDN Profiles", "description": "This module deploys a CDN Profile.", "owner": "Azure/module-maintainers" }, "definitions": { + "securityPolicyType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the security policy." + } + }, + "associations": { + "$ref": "#/definitions/associationsType", + "metadata": { + "description": "Required. Domain names and URL patterns to math with this association." + } + }, + "wafPolicyResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of WAF policy." + } + } + } + } + }, "lockType": { "type": "object", "properties": { @@ -110,6 +136,45 @@ } }, "nullable": true + }, + "associationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. ResourceID to domain that will be associated." + } + } + } + }, + "metadata": { + "description": "Required. List of domain resource id to associate with this resource." + } + }, + "patternsToMatch": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of patterns to match with this association." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "securityPolicies/main.bicep" + } + } } }, "parameters": { @@ -202,6 +267,13 @@ "description": "Optional. Array of AFD endpoint objects." } }, + "securityPolicies": { + "$ref": "#/definitions/securityPolicyType", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details)." + } + }, "tags": { "type": "object", "nullable": true, @@ -350,8 +422,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6371656015674390162" + "version": "0.30.23.60470", + "templateHash": "3460565146034921053" }, "name": "CDN Profiles Endpoints", "description": "This module deploys a CDN Profile Endpoint.", @@ -470,8 +542,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11976988406992266750" + "version": "0.30.23.60470", + "templateHash": "4151069688274070352" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", @@ -723,8 +795,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "533126228291817357" + "version": "0.30.23.60470", + "templateHash": "7661706938502506866" }, "name": "CDN Profiles Secret", "description": "This module deploys a CDN Profile Secret.", @@ -872,8 +944,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15211066835326278081" + "version": "0.30.23.60470", + "templateHash": "16955838730426729961" }, "name": "CDN Profiles Custom Domains", "description": "This module deploys a CDN Profile Custom Domains.", @@ -1039,8 +1111,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1182415535491789973" + "version": "0.30.23.60470", + "templateHash": "16948516107556143812" }, "name": "CDN Profiles Origin Group", "description": "This module deploys a CDN Profile Origin Group.", @@ -1176,8 +1248,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14493731512795008787" + "version": "0.30.23.60470", + "templateHash": "4669077701065465911" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", @@ -1402,8 +1474,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9792708426765797662" + "version": "0.30.23.60470", + "templateHash": "11520922481694023973" }, "name": "CDN Profiles Rule Sets", "description": "This module deploys a CDN Profile rule set.", @@ -1488,8 +1560,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12904222825428666192" + "version": "0.30.23.60470", + "templateHash": "8818585542646204223" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", @@ -1676,8 +1748,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3384292547879688658" + "version": "0.30.23.60470", + "templateHash": "792735746278824384" }, "name": "CDN Profiles AFD Endpoints", "description": "This module deploys a CDN Profile AFD Endpoint.", @@ -1827,8 +1899,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18002678880456924020" + "version": "0.30.23.60470", + "templateHash": "1034122698174669197" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", @@ -2119,6 +2191,168 @@ "profile_originGroups", "profile_ruleSets" ] + }, + "profile_securityPolicies": { + "copy": { + "name": "profile_securityPolicies", + "count": "[length(parameters('securityPolicies'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Profile-SecurityPolicy-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityPolicies')[copyIndex()].name]" + }, + "profileName": { + "value": "[parameters('name')]" + }, + "associations": { + "value": "[parameters('securityPolicies')[copyIndex()].associations]" + }, + "wafPolicyResourceId": { + "value": "[parameters('securityPolicies')[copyIndex()].wafPolicyResourceId]" + } + }, + "template": { + "$schema": "https://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": "11561080659040848436" + }, + "name": "CDN Profiles Security Policy", + "description": "This module deploys a CDN Profile Security Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "associationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. ResourceID to domain that will be associated." + } + } + } + }, + "metadata": { + "description": "Required. List of domain resource id to associate with this resource." + } + }, + "patternsToMatch": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of patterns to match with this association." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource name." + } + }, + "profileName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent CDN profile. Required if the template is used in a standalone deployment." + } + }, + "wafPolicyResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of WAF Policy." + } + }, + "associations": { + "$ref": "#/definitions/associationsType", + "metadata": { + "description": "Required. Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details)." + } + } + }, + "resources": { + "profile": { + "existing": true, + "type": "Microsoft.Cdn/profiles", + "apiVersion": "2023-05-01", + "name": "[parameters('profileName')]" + }, + "securityPolicies": { + "type": "Microsoft.Cdn/profiles/securityPolicies", + "apiVersion": "2024-02-01", + "name": "[format('{0}/{1}', parameters('profileName'), parameters('name'))]", + "properties": { + "parameters": { + "type": "WebApplicationFirewall", + "wafPolicy": { + "id": "[parameters('wafPolicyResourceId')]" + }, + "associations": "[parameters('associations')]" + } + }, + "dependsOn": [ + "profile" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secrect." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secrect." + }, + "value": "[resourceId('Microsoft.Cdn/profiles/securityPolicies', parameters('profileName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "profile", + "profile_afdEndpoints", + "profile_customDomains" + ] } }, "outputs": { diff --git a/avm/res/cdn/profile/origingroup/main.json b/avm/res/cdn/profile/origingroup/main.json index 9a388bc48e..af9a692a27 100644 --- a/avm/res/cdn/profile/origingroup/main.json +++ b/avm/res/cdn/profile/origingroup/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1182415535491789973" + "version": "0.30.23.60470", + "templateHash": "16948516107556143812" }, "name": "CDN Profiles Origin Group", "description": "This module deploys a CDN Profile Origin Group.", @@ -142,8 +142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14493731512795008787" + "version": "0.30.23.60470", + "templateHash": "4669077701065465911" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", diff --git a/avm/res/cdn/profile/origingroup/origin/main.json b/avm/res/cdn/profile/origingroup/origin/main.json index 56306ce135..8ee5bf04df 100644 --- a/avm/res/cdn/profile/origingroup/origin/main.json +++ b/avm/res/cdn/profile/origingroup/origin/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14493731512795008787" + "version": "0.30.23.60470", + "templateHash": "4669077701065465911" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", diff --git a/avm/res/cdn/profile/ruleset/main.json b/avm/res/cdn/profile/ruleset/main.json index 47ff335b1c..2d040690b5 100644 --- a/avm/res/cdn/profile/ruleset/main.json +++ b/avm/res/cdn/profile/ruleset/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9792708426765797662" + "version": "0.30.23.60470", + "templateHash": "11520922481694023973" }, "name": "CDN Profiles Rule Sets", "description": "This module deploys a CDN Profile rule set.", @@ -91,8 +91,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12904222825428666192" + "version": "0.30.23.60470", + "templateHash": "8818585542646204223" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", diff --git a/avm/res/cdn/profile/ruleset/rule/main.json b/avm/res/cdn/profile/ruleset/rule/main.json index bb37297681..98e0f0fef8 100644 --- a/avm/res/cdn/profile/ruleset/rule/main.json +++ b/avm/res/cdn/profile/ruleset/rule/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12904222825428666192" + "version": "0.30.23.60470", + "templateHash": "8818585542646204223" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", diff --git a/avm/res/cdn/profile/secret/main.json b/avm/res/cdn/profile/secret/main.json index a23afb02a0..6c300587db 100644 --- a/avm/res/cdn/profile/secret/main.json +++ b/avm/res/cdn/profile/secret/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "533126228291817357" + "version": "0.30.23.60470", + "templateHash": "7661706938502506866" }, "name": "CDN Profiles Secret", "description": "This module deploys a CDN Profile Secret.", diff --git a/avm/res/cdn/profile/securityPolicies/README.md b/avm/res/cdn/profile/securityPolicies/README.md new file mode 100644 index 0000000000..c30d3c5dad --- /dev/null +++ b/avm/res/cdn/profile/securityPolicies/README.md @@ -0,0 +1,101 @@ +# CDN Profiles Security Policy `[Microsoft.Cdn/profiles/securityPolicies]` + +This module deploys a CDN Profile Security Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Cdn/profiles/securityPolicies` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/profiles/securityPolicies) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`associations`](#parameter-associations) | array | Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details). | +| [`name`](#parameter-name) | string | The resource name. | +| [`wafPolicyResourceId`](#parameter-wafpolicyresourceid) | string | Resource ID of WAF Policy. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`profileName`](#parameter-profilename) | string | The name of the parent CDN profile. Required if the template is used in a standalone deployment. | + +### Parameter: `associations` + +Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details). + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domains`](#parameter-associationsdomains) | array | List of domain resource id to associate with this resource. | +| [`patternsToMatch`](#parameter-associationspatternstomatch) | array | List of patterns to match with this association. | + +### Parameter: `associations.domains` + +List of domain resource id to associate with this resource. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-associationsdomainsid) | string | ResourceID to domain that will be associated. | + +### Parameter: `associations.domains.id` + +ResourceID to domain that will be associated. + +- Required: Yes +- Type: string + +### Parameter: `associations.patternsToMatch` + +List of patterns to match with this association. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The resource name. + +- Required: Yes +- Type: string + +### Parameter: `wafPolicyResourceId` + +Resource ID of WAF Policy. + +- Required: Yes +- Type: string + +### Parameter: `profileName` + +The name of the parent CDN profile. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the secrect. | +| `resourceGroupName` | string | The name of the resource group the secret was created in. | +| `resourceId` | string | The resource ID of the secrect. | diff --git a/avm/res/cdn/profile/securityPolicies/main.bicep b/avm/res/cdn/profile/securityPolicies/main.bicep new file mode 100644 index 0000000000..1d98e235d9 --- /dev/null +++ b/avm/res/cdn/profile/securityPolicies/main.bicep @@ -0,0 +1,54 @@ +metadata name = 'CDN Profiles Security Policy' +metadata description = 'This module deploys a CDN Profile Security Policy.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The resource name.') +param name string + +@description('Conditional. The name of the parent CDN profile. Required if the template is used in a standalone deployment.') +param profileName string + +@description('Required. Resource ID of WAF Policy.') +param wafPolicyResourceId string + +// param associations associationsType +@description('Required. Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details).') +param associations associationsType + +resource profile 'Microsoft.Cdn/profiles@2023-05-01' existing = { + name: profileName +} + +resource securityPolicies 'Microsoft.Cdn/profiles/securityPolicies@2024-02-01' = { + name: name + parent: profile + properties: { + parameters: { + type: 'WebApplicationFirewall' + wafPolicy: { + id: wafPolicyResourceId + } + associations: associations + } + } +} + +@export() +type associationsType = { + @description('Required. List of domain resource id to associate with this resource.') + domains: { + @description('Required. ResourceID to domain that will be associated.') + id: string + }[] + @description('Required. List of patterns to match with this association.') + patternsToMatch: string[] +}[] + +@description('The name of the secrect.') +output name string = securityPolicies.name + +@description('The resource ID of the secrect.') +output resourceId string = securityPolicies.id + +@description('The name of the resource group the secret was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/cdn/profile/securityPolicies/main.json b/avm/res/cdn/profile/securityPolicies/main.json new file mode 100644 index 0000000000..be06e14c99 --- /dev/null +++ b/avm/res/cdn/profile/securityPolicies/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.30.23.60470", + "templateHash": "11561080659040848436" + }, + "name": "CDN Profiles Security Policy", + "description": "This module deploys a CDN Profile Security Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "associationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. ResourceID to domain that will be associated." + } + } + } + }, + "metadata": { + "description": "Required. List of domain resource id to associate with this resource." + } + }, + "patternsToMatch": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of patterns to match with this association." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource name." + } + }, + "profileName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent CDN profile. Required if the template is used in a standalone deployment." + } + }, + "wafPolicyResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of WAF Policy." + } + }, + "associations": { + "$ref": "#/definitions/associationsType", + "metadata": { + "description": "Required. Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details)." + } + } + }, + "resources": { + "profile": { + "existing": true, + "type": "Microsoft.Cdn/profiles", + "apiVersion": "2023-05-01", + "name": "[parameters('profileName')]" + }, + "securityPolicies": { + "type": "Microsoft.Cdn/profiles/securityPolicies", + "apiVersion": "2024-02-01", + "name": "[format('{0}/{1}', parameters('profileName'), parameters('name'))]", + "properties": { + "parameters": { + "type": "WebApplicationFirewall", + "wafPolicy": { + "id": "[parameters('wafPolicyResourceId')]" + }, + "associations": "[parameters('associations')]" + } + }, + "dependsOn": [ + "profile" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secrect." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secrect." + }, + "value": "[resourceId('Microsoft.Cdn/profiles/securityPolicies', parameters('profileName'), parameters('name'))]" + }, + "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/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep b/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep new file mode 100644 index 0000000000..e735b9c94b --- /dev/null +++ b/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep @@ -0,0 +1,146 @@ +targetScope = 'subscription' + +metadata name = 'As Azure Front Door Premium' +metadata description = 'This instance deploys the module as Azure Front Door Premium.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cdn.profiles-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdnpafdp' + +@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 wafPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:0.2.0' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-dep-waf-policy-${serviceShort}' + params: { + name: 'dep${namePrefix}${serviceShort}wafpolicy' + sku: 'Premium_AzureFrontDoor' + } +} + +// ============== // +// 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: 'dep-${namePrefix}-test-${serviceShort}' + location: 'global' + originResponseTimeoutSeconds: 60 + sku: 'Premium_AzureFrontDoor' + customDomains: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-custom-domain' + hostName: 'dep-${namePrefix}-test-${serviceShort}-custom-domain.azurewebsites.net' + certificateType: 'ManagedCertificate' + } + ] + originGroups: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-origin-group' + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + origins: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-origin' + hostName: 'dep-${namePrefix}-test-${serviceShort}-origin.azurewebsites.net' + } + ] + } + ] + ruleSets: [ + { + name: 'dep${namePrefix}test${serviceShort}ruleset' + rules: [ + { + name: 'dep${namePrefix}test${serviceShort}rule' + order: 1 + actions: [ + { + name: 'UrlRedirect' + parameters: { + typeName: 'DeliveryRuleUrlRedirectActionParameters' + redirectType: 'PermanentRedirect' + destinationProtocol: 'Https' + customPath: '/test123' + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + } + } + ] + } + ] + } + ] + afdEndpoints: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-afd-endpoint' + routes: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-afd-route' + originGroupName: 'dep-${namePrefix}-test-${serviceShort}-origin-group' + customDomainNames: ['dep-${namePrefix}-test-${serviceShort}-custom-domain'] + ruleSets: [ + { + name: 'dep${namePrefix}test${serviceShort}ruleset' + } + ] + } + ] + } + ] + securityPolicies: [ + { + name: 'dep${namePrefix}test${serviceShort}secpol' + associations: [ + { + domains: [ + { + id: resourceId( + subscription().subscriptionId, + resourceGroup.name, + 'Microsoft.Cdn/profiles/afdEndpoints', + 'dep-${namePrefix}-test-${serviceShort}', + 'dep-${namePrefix}-test-${serviceShort}-afd-endpoint' + ) + } + ] + patternsToMatch: [ + '/*' + ] + } + ] + wafPolicyResourceId: wafPolicy.outputs.resourceId + } + ] + } + } +] diff --git a/avm/res/cdn/profile/version.json b/avm/res/cdn/profile/version.json index a8eda31021..9ed3662aba 100644 --- a/avm/res/cdn/profile/version.json +++ b/avm/res/cdn/profile/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.5", + "version": "0.6", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} From 7d6600c6f44a279832d5bd7497fed0dc617e89eb Mon Sep 17 00:00:00 2001 From: mortenvpschmidt <47330927+mortenvpschmidt@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:34:30 +0200 Subject: [PATCH 26/93] fix: Add key vault to search service - `avm/res/search/search-service` (#1950) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add option for outputting admin keys to search service ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.search.search-service](https://github.com/mortenvpschmidt/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml/badge.svg?branch=Aisearch_w_keyvault)](https://github.com/mortenvpschmidt/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module effecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Morten Schmidt Co-authored-by: Axel Bøg Andersen Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/search/search-service/README.md | 138 ++++++++++- avm/res/search/search-service/main.bicep | 64 ++++- avm/res/search/search-service/main.json | 223 ++++++++++++++++-- .../modules/keyVaultExport.bicep | 62 +++++ .../tests/e2e/kvSecrets/dependencies.bicep | 21 ++ .../tests/e2e/kvSecrets/main.test.bicep | 62 +++++ .../tests/e2e/pe/main.test.bicep | 2 +- 7 files changed, 535 insertions(+), 37 deletions(-) create mode 100644 avm/res/search/search-service/modules/keyVaultExport.bicep create mode 100644 avm/res/search/search-service/tests/e2e/kvSecrets/dependencies.bicep create mode 100644 avm/res/search/search-service/tests/e2e/kvSecrets/main.test.bicep diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md index 9001f0359c..e8645d04a5 100644 --- a/avm/res/search/search-service/README.md +++ b/avm/res/search/search-service/README.md @@ -18,6 +18,7 @@ This module deploys a Search Service. | `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.Search/searchServices` | [2024-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2024-03-01-preview/searchServices) | @@ -32,9 +33,10 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/search/search-service:`. - [Using only defaults](#example-1-using-only-defaults) -- [Using large parameter set](#example-2-using-large-parameter-set) -- [Private endpoint-enabled deployment](#example-3-private-endpoint-enabled-deployment) -- [WAF-aligned](#example-4-waf-aligned) +- [Deploying with a key vault reference to save secrets](#example-2-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Private endpoint-enabled deployment](#example-4-private-endpoint-enabled-deployment) +- [WAF-aligned](#example-5-waf-aligned) ### Example 1: _Using only defaults_ @@ -84,7 +86,83 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-### Example 2: _Using large parameter set_ +### Example 2: _Deploying with a key vault reference to save secrets_ + +This instance deploys the module saving admin key secrets in a key vault. + + +

+ +via Bicep module + +```bicep +module searchService 'br/public:avm/res/search/search-service:' = { + name: 'searchServiceDeployment' + params: { + // Required parameters + name: 'kv-ref' + // Non-required parameters + authOptions: { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } + } + disableLocalAuth: false + location: '' + secretsExportConfiguration: { + keyVaultResourceId: '' + primaryAdminKeyName: 'Primary-Admin-Key' + secondaryAdminKeyName: 'Secondary-Admin-Key' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "kv-ref" + }, + // Non-required parameters + "authOptions": { + "value": { + "aadOrApiKey": { + "aadAuthFailureMode": "http401WithBearerChallenge" + } + } + }, + "disableLocalAuth": { + "value": false + }, + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "keyVaultResourceId": "", + "primaryAdminKeyName": "Primary-Admin-Key", + "secondaryAdminKeyName": "Secondary-Admin-Key" + } + } + } +} +``` + +
+

+ +### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -300,7 +378,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-### Example 3: _Private endpoint-enabled deployment_ +### Example 4: _Private endpoint-enabled deployment_ This instance deploys the module with private endpoints. @@ -314,7 +392,7 @@ module searchService 'br/public:avm/res/search/search-service:' = { name: 'searchServiceDeployment' params: { // Required parameters - name: 'ssspe001' + name: 'ssspr001' // Non-required parameters location: '' privateEndpoints: [ @@ -383,7 +461,7 @@ module searchService 'br/public:avm/res/search/search-service:' = { "parameters": { // Required parameters "name": { - "value": "ssspe001" + "value": "ssspr001" }, // Non-required parameters "location": { @@ -452,7 +530,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-### Example 4: _WAF-aligned_ +### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -645,6 +723,7 @@ module searchService 'br/public:avm/res/search/search-service:' = { | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method. | | [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | | [`semanticSearch`](#parameter-semanticsearch) | string | Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. | | [`sharedPrivateLinkResources`](#parameter-sharedprivatelinkresources) | array | The sharedPrivateLinkResources to create as part of the search Service. | | [`sku`](#parameter-sku) | string | Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits. | @@ -1481,6 +1560,47 @@ The principal type of the assigned principal ID. ] ``` +### 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 API Admin keys generated by the modules. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`primaryAdminKeyName`](#parameter-secretsexportconfigurationprimaryadminkeyname) | string | The primaryAdminKey secret name to create. | +| [`secondaryAdminKeyName`](#parameter-secretsexportconfigurationsecondaryadminkeyname) | string | The secondaryAdminKey secret name to create. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The key vault name where to store the API Admin keys generated by the modules. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.primaryAdminKeyName` + +The primaryAdminKey secret name to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.secondaryAdminKeyName` + +The secondaryAdminKey secret name to create. + +- Required: No +- Type: string + ### Parameter: `semanticSearch` Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. @@ -1535,9 +1655,9 @@ Tags to help categorize the resource in the Azure portal. | 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 search service. | -| `privateEndpoints` | array | The private endpoints of the search service. | | `resourceGroupName` | string | The name of the resource group the search service was created in. | | `resourceId` | string | The resource ID of the search service. | | `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | diff --git a/avm/res/search/search-service/main.bicep b/avm/res/search/search-service/main.bicep index 951adfe725..df608c8af6 100644 --- a/avm/res/search/search-service/main.bicep +++ b/avm/res/search/search-service/main.bicep @@ -60,6 +60,9 @@ param sharedPrivateLinkResources array = [] ]) param publicNetworkAccess string = 'Enabled' +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + @description('Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU.') @minValue(1) @maxValue(12) @@ -324,6 +327,36 @@ module searchService_sharedPrivateLinkResources 'shared-private-link-resource/ma } ] +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!, 'primaryAdminKeyName') + ? [ + { + name: secretsExportConfiguration!.primaryAdminKeyName + value: searchService.listAdminKeys().primaryKey + } + ] + : [], + contains(secretsExportConfiguration!, 'secondaryAdminKeyName') + ? [ + { + name: secretsExportConfiguration!.secondaryAdminKeyName + value: searchService.listAdminKeys().secondaryKey + } + ] + : [] + ) + } +} + // =========== // // Outputs // // =========== // @@ -343,16 +376,10 @@ output systemAssignedMIPrincipalId string = searchService.?identity.?principalId @description('The location the resource was deployed into.') output location string = searchService.location -@description('The private endpoints of the search service.') -output privateEndpoints array = [ - for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { - name: searchService_privateEndpoints[i].outputs.name - resourceId: searchService_privateEndpoints[i].outputs.resourceId - groupId: searchService_privateEndpoints[i].outputs.groupId - customDnsConfig: searchService_privateEndpoints[i].outputs.customDnsConfig - networkInterfaceIds: searchService_privateEndpoints[i].outputs.networkInterfaceIds - } -] +@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 // @@ -530,3 +557,20 @@ type diagnosticSettingType = { @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') marketplacePartnerResourceId: string? }[]? + +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the API Admin keys generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The primaryAdminKey secret name to create.') + primaryAdminKeyName: string? + + @description('Optional. The secondaryAdminKey secret name to create.') + secondaryAdminKeyName: string? +} + +import { secretSetType } from 'modules/keyVaultExport.bicep' +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/res/search/search-service/main.json b/avm/res/search/search-service/main.json index c4b625ff47..24719a5ca7 100644 --- a/avm/res/search/search-service/main.json +++ b/avm/res/search/search-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8483667347070963331" + "version": "0.30.23.60470", + "templateHash": "13527260085574333800" }, "name": "Search Services", "description": "This module deploys a Search Service.", @@ -473,6 +473,63 @@ } }, "nullable": true + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the API Admin keys generated by the modules." + } + }, + "primaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAdminKey secret name to create." + } + }, + "secondaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAdminKey secret name to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "secretSetType": { + "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." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } } }, "parameters": { @@ -579,6 +636,13 @@ "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." } }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, "replicaCount": { "type": "int", "defaultValue": 3, @@ -1593,8 +1657,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2330033720810948871" + "version": "0.30.23.60470", + "templateHash": "1073269867332822875" }, "name": "Search Services Private Link Resources", "description": "This module deploys a Search Service Private Link Resource.", @@ -1689,6 +1753,140 @@ "dependsOn": [ "searchService" ] + }, + "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'), 'primaryAdminKeyName'), createArray(createObject('name', parameters('secretsExportConfiguration').primaryAdminKeyName, 'value', listAdminKeys(resourceId('Microsoft.Search/searchServices', parameters('name')), '2024-03-01-preview').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', parameters('secretsExportConfiguration').secondaryAdminKeyName, 'value', listAdminKeys(resourceId('Microsoft.Search/searchServices', parameters('name')), '2024-03-01-preview').secondaryKey)), 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.30.23.60470", + "templateHash": "12263717469683062316" + } + }, + "definitions": { + "secretSetType": { + "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." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "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." + } + } + } + } + }, + "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]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "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]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] } }, "outputs": { @@ -1727,21 +1925,12 @@ }, "value": "[reference('searchService', '2024-03-01-preview', 'full').location]" }, - "privateEndpoints": { - "type": "array", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "The private endpoints of the search service." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "copy": { - "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", - "input": { - "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", - "customDnsConfig": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", - "networkInterfaceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" - } - } + "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/res/search/search-service/modules/keyVaultExport.bicep b/avm/res/search/search-service/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..d537d2407e --- /dev/null +++ b/avm/res/search/search-service/modules/keyVaultExport.bicep @@ -0,0 +1,62 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the ecrets in.') +param keyVaultName string + +@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 // +// =========== // + +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetType[] = [ + #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 + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string +} + +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} diff --git a/avm/res/search/search-service/tests/e2e/kvSecrets/dependencies.bicep b/avm/res/search/search-service/tests/e2e/kvSecrets/dependencies.bicep new file mode 100644 index 0000000000..da0b29e26f --- /dev/null +++ b/avm/res/search/search-service/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 key vault id of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/search/search-service/tests/e2e/kvSecrets/main.test.bicep b/avm/res/search/search-service/tests/e2e/kvSecrets/main.test.bicep new file mode 100644 index 0000000000..cdd93d36cd --- /dev/null +++ b/avm/res/search/search-service/tests/e2e/kvSecrets/main.test.bicep @@ -0,0 +1,62 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a key vault reference to save secrets' +metadata description = 'This instance deploys the module saving admin key 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}-search.searchservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssskvs' + +@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}-kv-ref' + disableLocalAuth: false + authOptions: { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } + } + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + primaryAdminKeyName: 'Primary-Admin-Key' + secondaryAdminKeyName: 'Secondary-Admin-Key' + } + } +} diff --git a/avm/res/search/search-service/tests/e2e/pe/main.test.bicep b/avm/res/search/search-service/tests/e2e/pe/main.test.bicep index 185cd85d5f..76fecb0274 100644 --- a/avm/res/search/search-service/tests/e2e/pe/main.test.bicep +++ b/avm/res/search/search-service/tests/e2e/pe/main.test.bicep @@ -15,7 +15,7 @@ param resourceGroupName string = 'dep-${namePrefix}-search.searchservices-${serv param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'ssspe' +param serviceShort string = 'ssspr' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' From 262267189fb68262ed529d90979d9d2ccc21f0b9 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 1 Oct 2024 16:36:27 +0200 Subject: [PATCH 27/93] feat: DataFactory - Added UDTs (#3117) ## Description Follow-up to #2763 --- Quote: @donheerschap Added UDTs for: Managed Private Endpoints Integration Runtimes Linked Services For a better dev experience. > Edit: @AlexanderSehr also addressed linter warnings ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.data-factory.factory](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml/badge.svg?branch=users%2Falsehr%2Fdonheerschap%2Fadd-adf-udts&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --------- Co-authored-by: Don Heerschap --- avm/res/data-factory/factory/README.md | 161 ++++++++++++++++- .../factory/integration-runtime/main.json | 4 +- .../factory/linked-service/main.bicep | 1 + .../factory/linked-service/main.json | 4 +- avm/res/data-factory/factory/main.bicep | 68 ++++++- avm/res/data-factory/factory/main.json | 166 ++++++++++++++++-- .../factory/managed-virtual-network/main.json | 8 +- .../managed-private-endpoint/main.json | 4 +- .../factory/tests/e2e/max/main.test.bicep | 2 +- 9 files changed, 381 insertions(+), 37 deletions(-) diff --git a/avm/res/data-factory/factory/README.md b/avm/res/data-factory/factory/README.md index bd9ec6e1c6..4f12df906f 100644 --- a/avm/res/data-factory/factory/README.md +++ b/avm/res/data-factory/factory/README.md @@ -165,7 +165,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = { } type: 'AzureBlobFS' typeProperties: { - url: '@{concat(\'https://\', linkedService().storageAccountName, \'.dfs.core.windows.net\')}' + url: '' } } ] @@ -335,7 +335,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = { }, "type": "AzureBlobFS", "typeProperties": { - "url": "@{concat(\"https://\", linkedService().storageAccountName, \".dfs.core.windows.net\")}" + "url": "" } } ] @@ -884,6 +884,63 @@ An array of objects for the configuration of an Integration Runtime. - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-integrationruntimesname) | string | Specify the name of integration runtime. | +| [`type`](#parameter-integrationruntimestype) | string | Specify the type of the integration runtime. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`integrationRuntimeCustomDescription`](#parameter-integrationruntimesintegrationruntimecustomdescription) | string | Specify custom description for the integration runtime. | +| [`managedVirtualNetworkName`](#parameter-integrationruntimesmanagedvirtualnetworkname) | string | Specify managed vritual network name for the integration runtime to link to. | +| [`typeProperties`](#parameter-integrationruntimestypeproperties) | object | Integration Runtime type properties. Required if type is "Managed". | + +### Parameter: `integrationRuntimes.name` + +Specify the name of integration runtime. + +- Required: Yes +- Type: string + +### Parameter: `integrationRuntimes.type` + +Specify the type of the integration runtime. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Managed' + 'SelfHosted' + ] + ``` + +### Parameter: `integrationRuntimes.integrationRuntimeCustomDescription` + +Specify custom description for the integration runtime. + +- Required: No +- Type: string + +### Parameter: `integrationRuntimes.managedVirtualNetworkName` + +Specify managed vritual network name for the integration runtime to link to. + +- Required: No +- Type: string + +### Parameter: `integrationRuntimes.typeProperties` + +Integration Runtime type properties. Required if type is "Managed". + +- Required: No +- Type: object + ### Parameter: `linkedServices` An array of objects for the configuration of Linked Services. @@ -892,6 +949,64 @@ An array of objects for the configuration of Linked Services. - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-linkedservicesname) | string | The name of the Linked Service. | +| [`type`](#parameter-linkedservicestype) | string | The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-linkedservicesdescription) | string | The description of the Integration Runtime. | +| [`integrationRuntimeName`](#parameter-linkedservicesintegrationruntimename) | string | The name of the Integration Runtime to use. | +| [`parameters`](#parameter-linkedservicesparameters) | object | Use this to add parameters for a linked service connection string. | +| [`typeProperties`](#parameter-linkedservicestypeproperties) | object | Used to add connection properties for your linked services. | + +### Parameter: `linkedServices.name` + +The name of the Linked Service. + +- Required: Yes +- Type: string + +### Parameter: `linkedServices.type` + +The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information. + +- Required: Yes +- Type: string + +### Parameter: `linkedServices.description` + +The description of the Integration Runtime. + +- Required: No +- Type: string + +### Parameter: `linkedServices.integrationRuntimeName` + +The name of the Integration Runtime to use. + +- Required: No +- Type: string + +### Parameter: `linkedServices.parameters` + +Use this to add parameters for a linked service connection string. + +- Required: No +- Type: object + +### Parameter: `linkedServices.typeProperties` + +Used to add connection properties for your linked services. + +- Required: No +- Type: object + ### Parameter: `location` Location for all Resources. @@ -972,6 +1087,48 @@ An array of managed private endpoints objects created in the Data Factory manage - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-managedprivateendpointsgroupid) | string | Specify the sub-resource of the managed private endpoint. | +| [`name`](#parameter-managedprivateendpointsname) | string | Specify the name of managed private endpoint. | +| [`privateLinkResourceId`](#parameter-managedprivateendpointsprivatelinkresourceid) | string | Specify the resource ID to create the managed private endpoint for. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdns`](#parameter-managedprivateendpointsfqdns) | array | Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required. | + +### Parameter: `managedPrivateEndpoints.groupId` + +Specify the sub-resource of the managed private endpoint. + +- Required: Yes +- Type: string + +### Parameter: `managedPrivateEndpoints.name` + +Specify the name of managed private endpoint. + +- Required: Yes +- Type: string + +### Parameter: `managedPrivateEndpoints.privateLinkResourceId` + +Specify the resource ID to create the managed private endpoint for. + +- Required: Yes +- Type: string + +### Parameter: `managedPrivateEndpoints.fqdns` + +Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required. + +- Required: No +- Type: array + ### Parameter: `managedVirtualNetworkName` The name of the Managed Virtual Network. diff --git a/avm/res/data-factory/factory/integration-runtime/main.json b/avm/res/data-factory/factory/integration-runtime/main.json index 991ffcaaa3..2db2b0af74 100644 --- a/avm/res/data-factory/factory/integration-runtime/main.json +++ b/avm/res/data-factory/factory/integration-runtime/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7050455062079134223" + "version": "0.30.23.60470", + "templateHash": "17201448291064419524" }, "name": "Data Factory Integration RunTimes", "description": "This module deploys a Data Factory Managed or Self-Hosted Integration Runtime.", diff --git a/avm/res/data-factory/factory/linked-service/main.bicep b/avm/res/data-factory/factory/linked-service/main.bicep index af51a01544..5748e4582f 100644 --- a/avm/res/data-factory/factory/linked-service/main.bicep +++ b/avm/res/data-factory/factory/linked-service/main.bicep @@ -41,6 +41,7 @@ resource linkedService 'Microsoft.DataFactory/factories/linkedservices@2018-06-0 referenceName: integrationRuntimeName type: 'IntegrationRuntimeReference' } + #disable-next-line BCP225 // false-positive as 'type' is interpreted as a syntax value type: type typeProperties: typeProperties parameters: parameters diff --git a/avm/res/data-factory/factory/linked-service/main.json b/avm/res/data-factory/factory/linked-service/main.json index c44e38f1ed..12ca641d7d 100644 --- a/avm/res/data-factory/factory/linked-service/main.json +++ b/avm/res/data-factory/factory/linked-service/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2964661488202892260" + "version": "0.30.23.60470", + "templateHash": "5456106394920661740" }, "name": "Data Factory Linked Service", "description": "This module deploys a Data Factory Linked Service.", diff --git a/avm/res/data-factory/factory/main.bicep b/avm/res/data-factory/factory/main.bicep index 7b24ccaf43..5bb934d5a0 100644 --- a/avm/res/data-factory/factory/main.bicep +++ b/avm/res/data-factory/factory/main.bicep @@ -9,13 +9,13 @@ param name string param managedVirtualNetworkName string = '' @description('Optional. An array of managed private endpoints objects created in the Data Factory managed virtual network.') -param managedPrivateEndpoints array = [] +param managedPrivateEndpoints managedPrivateEndpointType[] = [] @description('Optional. An array of objects for the configuration of an Integration Runtime.') -param integrationRuntimes array = [] +param integrationRuntimes integrationRuntimesType = [] @description('Optional. An array of objects for the configuration of Linked Services.') -param linkedServices array = [] +param linkedServices linkedServicesType = [] @description('Optional. Location for all Resources.') param location string = resourceGroup().location @@ -235,11 +235,9 @@ module dataFactory_integrationRuntimes 'integration-runtime/main.bicep' = [ dataFactoryName: dataFactory.name name: integrationRuntime.name type: integrationRuntime.type - integrationRuntimeCustomDescription: integrationRuntime.?integrationRuntimeCustomDescription ?? 'Managed Integration Runtime created by avm-res-datafactory-factories' - managedVirtualNetworkName: contains(integrationRuntime, 'managedVirtualNetworkName') - ? integrationRuntime.managedVirtualNetworkName - : '' - typeProperties: contains(integrationRuntime, 'typeProperties') ? integrationRuntime.typeProperties : {} + integrationRuntimeCustomDescription: integrationRuntime.?integrationRuntimeCustomDescription + managedVirtualNetworkName: integrationRuntime.?managedVirtualNetworkName + typeProperties: integrationRuntime.?typeProperties } dependsOn: [ dataFactory_managedVirtualNetwork @@ -259,6 +257,9 @@ module dataFactory_linkedServices 'linked-service/main.bicep' = [ parameters: linkedService.?parameters description: linkedService.?description } + dependsOn: [ + dataFactory_integrationRuntimes + ] } ] @@ -586,3 +587,54 @@ type customerManagedKeyType = { @description('Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use.') userAssignedIdentityResourceId: string? }? + +type managedPrivateEndpointType = { + @description('Required. Specify the name of managed private endpoint.') + name: string + + @description('Required. Specify the sub-resource of the managed private endpoint.') + groupId: string + + @description('Required. Specify the resource ID to create the managed private endpoint for.') + privateLinkResourceId: string + + @description('Optional. Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required.') + fqdns: string[]? +} + +type integrationRuntimesType = { + @description('Required. Specify the name of integration runtime.') + name: string + + @description('Required. Specify the type of the integration runtime.') + type: ('Managed' | 'SelfHosted') + + @description('Optional. Specify custom description for the integration runtime.') + integrationRuntimeCustomDescription: string? + + @description('Optional. Specify managed vritual network name for the integration runtime to link to.') + managedVirtualNetworkName: string? + + @description('Optional. Integration Runtime type properties. Required if type is "Managed".') + typeProperties: object? +}[] + +type linkedServicesType = { + @description('Required. The name of the Linked Service.') + name: string + + @description('Required. The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information.') + type: string + + @description('Optional. Used to add connection properties for your linked services.') + typeProperties: object? + + @description('Optional. The name of the Integration Runtime to use.') + integrationRuntimeName: string? + + @description('Optional. Use this to add parameters for a linked service connection string.') + parameters: object? + + @description('Optional. The description of the Integration Runtime.') + description: string? +}[] diff --git a/avm/res/data-factory/factory/main.json b/avm/res/data-factory/factory/main.json index 310b27936e..5e8ffea4e0 100644 --- a/avm/res/data-factory/factory/main.json +++ b/avm/res/data-factory/factory/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18076044993800210191" + "version": "0.30.23.60470", + "templateHash": "15687596888855868361" }, "name": "Data Factories", "description": "This module deploys a Data Factory.", @@ -505,6 +505,132 @@ } }, "nullable": true + }, + "managedPrivateEndpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specify the name of managed private endpoint." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. Specify the sub-resource of the managed private endpoint." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Specify the resource ID to create the managed private endpoint for." + } + }, + "fqdns": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required." + } + } + } + }, + "integrationRuntimesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specify the name of integration runtime." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Managed", + "SelfHosted" + ], + "metadata": { + "description": "Required. Specify the type of the integration runtime." + } + }, + "integrationRuntimeCustomDescription": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify custom description for the integration runtime." + } + }, + "managedVirtualNetworkName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify managed vritual network name for the integration runtime to link to." + } + }, + "typeProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Integration Runtime type properties. Required if type is \"Managed\"." + } + } + } + } + }, + "linkedServicesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Linked Service." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information." + } + }, + "typeProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Used to add connection properties for your linked services." + } + }, + "integrationRuntimeName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Integration Runtime to use." + } + }, + "parameters": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Use this to add parameters for a linked service connection string." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the Integration Runtime." + } + } + } + } } }, "parameters": { @@ -523,20 +649,23 @@ }, "managedPrivateEndpoints": { "type": "array", + "items": { + "$ref": "#/definitions/managedPrivateEndpointType" + }, "defaultValue": [], "metadata": { "description": "Optional. An array of managed private endpoints objects created in the Data Factory managed virtual network." } }, "integrationRuntimes": { - "type": "array", + "$ref": "#/definitions/integrationRuntimesType", "defaultValue": [], "metadata": { "description": "Optional. An array of objects for the configuration of an Integration Runtime." } }, "linkedServices": { - "type": "array", + "$ref": "#/definitions/linkedServicesType", "defaultValue": [], "metadata": { "description": "Optional. An array of objects for the configuration of Linked Services." @@ -888,8 +1017,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17839923462414788715" + "version": "0.30.23.60470", + "templateHash": "1782105630855230474" }, "name": "Data Factory Managed Virtual Networks", "description": "This module deploys a Data Factory Managed Virtual Network.", @@ -962,8 +1091,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3694105160445163406" + "version": "0.30.23.60470", + "templateHash": "6720514642858120112" }, "name": "Data Factory Managed Virtual Network Managed PrivateEndpoints", "description": "This module deploys a Data Factory Managed Virtual Network Managed Private Endpoint.", @@ -1099,10 +1228,14 @@ "value": "[parameters('integrationRuntimes')[copyIndex()].type]" }, "integrationRuntimeCustomDescription": { - "value": "[coalesce(tryGet(parameters('integrationRuntimes')[copyIndex()], 'integrationRuntimeCustomDescription'), 'Managed Integration Runtime created by avm-res-datafactory-factories')]" + "value": "[tryGet(parameters('integrationRuntimes')[copyIndex()], 'integrationRuntimeCustomDescription')]" }, - "managedVirtualNetworkName": "[if(contains(parameters('integrationRuntimes')[copyIndex()], 'managedVirtualNetworkName'), createObject('value', parameters('integrationRuntimes')[copyIndex()].managedVirtualNetworkName), createObject('value', ''))]", - "typeProperties": "[if(contains(parameters('integrationRuntimes')[copyIndex()], 'typeProperties'), createObject('value', parameters('integrationRuntimes')[copyIndex()].typeProperties), createObject('value', createObject()))]" + "managedVirtualNetworkName": { + "value": "[tryGet(parameters('integrationRuntimes')[copyIndex()], 'managedVirtualNetworkName')]" + }, + "typeProperties": { + "value": "[tryGet(parameters('integrationRuntimes')[copyIndex()], 'typeProperties')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1110,8 +1243,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7050455062079134223" + "version": "0.30.23.60470", + "templateHash": "17201448291064419524" }, "name": "Data Factory Integration RunTimes", "description": "This module deploys a Data Factory Managed or Self-Hosted Integration Runtime.", @@ -1248,8 +1381,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2964661488202892260" + "version": "0.30.23.60470", + "templateHash": "5456106394920661740" }, "name": "Data Factory Linked Service", "description": "This module deploys a Data Factory Linked Service.", @@ -1344,7 +1477,8 @@ } }, "dependsOn": [ - "dataFactory" + "dataFactory", + "dataFactory_integrationRuntimes" ] }, "dataFactory_privateEndpoints": { diff --git a/avm/res/data-factory/factory/managed-virtual-network/main.json b/avm/res/data-factory/factory/managed-virtual-network/main.json index f84cc1629b..22a3f54962 100644 --- a/avm/res/data-factory/factory/managed-virtual-network/main.json +++ b/avm/res/data-factory/factory/managed-virtual-network/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17839923462414788715" + "version": "0.30.23.60470", + "templateHash": "1782105630855230474" }, "name": "Data Factory Managed Virtual Networks", "description": "This module deploys a Data Factory Managed Virtual Network.", @@ -78,8 +78,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3694105160445163406" + "version": "0.30.23.60470", + "templateHash": "6720514642858120112" }, "name": "Data Factory Managed Virtual Network Managed PrivateEndpoints", "description": "This module deploys a Data Factory Managed Virtual Network Managed Private Endpoint.", diff --git a/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json b/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json index 28c3cf639b..c9c9e60513 100644 --- a/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json +++ b/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3694105160445163406" + "version": "0.30.23.60470", + "templateHash": "6720514642858120112" }, "name": "Data Factory Managed Virtual Network Managed PrivateEndpoints", "description": "This module deploys a Data Factory Managed Virtual Network Managed Private Endpoint.", diff --git a/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep b/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep index 03a1f38a74..a134efefe6 100644 --- a/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep +++ b/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep @@ -136,7 +136,7 @@ module testDeployment '../../../main.bicep' = [ } type: 'AzureBlobFS' typeProperties: { - url: '@{concat(\'https://\', linkedService().storageAccountName, \'.dfs.core.windows.net\')}' + url: '@{concat(\'https://\', linkedService().storageAccountName, \'.dfs.${environment().suffixes.storage}\')}' } } ] From 44c2f98d2259b42424707cb6a032a6c6ec3f47ea Mon Sep 17 00:00:00 2001 From: Kris Baranek <20225789+krbar@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:50:52 +0200 Subject: [PATCH 28/93] fix: `prefixLength` minimum value in `avm/res/network/public-ip-prefix` (#3382) ## Description Updates the minimum value of the `prefixLength` parameter to `/21` as per: - https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/public-ip-address-prefix > If you are [deriving a Public IP Prefix from a Custom IP Prefix (BYOIP range)](https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/manage-custom-ip-address-prefix#create-a-public-ip-prefix-from-a-custom-ip-prefix), the prefix size can be as large as the Custom IP Prefix. - https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/custom-ip-address-prefix : > A custom IPv4 Prefix must be between /21 and /24 Fixes #3367 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.public-ip-prefix](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml/badge.svg?branch=users%2Fkrbar%2FpfxFix)](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/network/public-ip-prefix/main.bicep | 2 +- avm/res/network/public-ip-prefix/main.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/avm/res/network/public-ip-prefix/main.bicep b/avm/res/network/public-ip-prefix/main.bicep index ce7ae8941a..f53aaf8b6c 100644 --- a/avm/res/network/public-ip-prefix/main.bicep +++ b/avm/res/network/public-ip-prefix/main.bicep @@ -10,7 +10,7 @@ param name string param location string = resourceGroup().location @description('Required. Length of the Public IP Prefix.') -@minValue(28) +@minValue(21) @maxValue(31) param prefixLength int diff --git a/avm/res/network/public-ip-prefix/main.json b/avm/res/network/public-ip-prefix/main.json index f3c6be1419..31a4295388 100644 --- a/avm/res/network/public-ip-prefix/main.json +++ b/avm/res/network/public-ip-prefix/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2074867794511783977" + "version": "0.30.23.60470", + "templateHash": "13346619343009869073" }, "name": "Public IP Prefixes", "description": "This module deploys a Public IP Prefix.", @@ -129,7 +129,7 @@ }, "prefixLength": { "type": "int", - "minValue": 28, + "minValue": 21, "maxValue": 31, "metadata": { "description": "Required. Length of the Public IP Prefix." From 7a2ea326c105d14c8e9ebc1fa8d4b26ff2956a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wenjie=20Yu=EF=BC=88MSFT=EF=BC=89?= <81678720+zedy-wj@users.noreply.github.com> Date: Wed, 2 Oct 2024 02:15:36 +0800 Subject: [PATCH 29/93] feat: Add new module `document-db/mongo-cluster` (#2790) ## Description Related PR: https://github.com/Azure/azure-dev/pull/3507 Add a new module `document-db/mongo-cluster` to support new feature. ## Pipeline Reference | Pipeline | | -------- | |[![avm.res.document-db.mongo-cluster](https://github.com/zedy-wj/bicep-registry-modules/actions/workflows/avm.res.document-db.mongo-cluster.yml/badge.svg?branch=document-db%2FmongoClusters)](https://github.com/zedy-wj/bicep-registry-modules/actions/workflows/avm.res.document-db.mongo-cluster.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio - for notification. --------- Co-authored-by: zedy Co-authored-by: Menghua Chen (WICRESOFT NORTH AMERICA LTD) Co-authored-by: Menghua Chen (MSFT) <111940661+Menghua1@users.noreply.github.com> Co-authored-by: Yohan Lasorsa --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.res.document-db.mongo-cluster.yml | 88 + avm/res/document-db/mongo-cluster/README.md | 1393 ++++++++++++ .../mongo-cluster/firewall-rule/README.md | 67 + .../mongo-cluster/firewall-rule/main.bicep | 37 + .../mongo-cluster/firewall-rule/main.json | 74 + avm/res/document-db/mongo-cluster/main.bicep | 535 +++++ avm/res/document-db/mongo-cluster/main.json | 1898 +++++++++++++++++ .../modules/keyVaultExport.bicep | 50 + .../tests/e2e/defaults/main.test.bicep | 57 + .../tests/e2e/kvSecrets/dependencies.bicep | 21 + .../tests/e2e/kvSecrets/main.test.bicep | 72 + .../tests/e2e/max/dependencies.bicep | 102 + .../tests/e2e/max/main.test.bicep | 163 ++ .../tests/e2e/waf-aligned/main.test.bicep | 57 + .../document-db/mongo-cluster/version.json | 7 + 17 files changed, 4623 insertions(+) create mode 100644 .github/workflows/avm.res.document-db.mongo-cluster.yml create mode 100644 avm/res/document-db/mongo-cluster/README.md create mode 100644 avm/res/document-db/mongo-cluster/firewall-rule/README.md create mode 100644 avm/res/document-db/mongo-cluster/firewall-rule/main.bicep create mode 100644 avm/res/document-db/mongo-cluster/firewall-rule/main.json create mode 100644 avm/res/document-db/mongo-cluster/main.bicep create mode 100644 avm/res/document-db/mongo-cluster/main.json create mode 100644 avm/res/document-db/mongo-cluster/modules/keyVaultExport.bicep create mode 100644 avm/res/document-db/mongo-cluster/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/dependencies.bicep create mode 100644 avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/main.test.bicep create mode 100644 avm/res/document-db/mongo-cluster/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/document-db/mongo-cluster/tests/e2e/max/main.test.bicep create mode 100644 avm/res/document-db/mongo-cluster/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/document-db/mongo-cluster/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fff88d76bc..2e2123c29c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -66,6 +66,7 @@ /avm/res/dev-test-lab/lab/ @Azure/avm-res-devtestlab-lab-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/digital-twins/digital-twins-instance/ @Azure/avm-res-digitaltwins-digitaltwinsinstance-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/document-db/database-account/ @Azure/avm-res-documentdb-databaseaccount-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/document-db/mongo-cluster/ @Azure/avm-res-documentdb-mongocluster-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/domain/ @Azure/avm-res-eventgrid-domain-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/namespace/ @Azure/avm-res-eventgrid-namespace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/system-topic/ @Azure/avm-res-eventgrid-systemtopic-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index feded8d600..d9e7855858 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -101,6 +101,7 @@ body: - "avm/res/dev-test-lab/lab" - "avm/res/digital-twins/digital-twins-instance" - "avm/res/document-db/database-account" + - "avm/res/document-db/mongo-cluster" - "avm/res/event-grid/domain" - "avm/res/event-grid/namespace" - "avm/res/event-grid/system-topic" diff --git a/.github/workflows/avm.res.document-db.mongo-cluster.yml b/.github/workflows/avm.res.document-db.mongo-cluster.yml new file mode 100644 index 0000000000..f7b513ae03 --- /dev/null +++ b/.github/workflows/avm.res.document-db.mongo-cluster.yml @@ -0,0 +1,88 @@ +name: "avm.res.document-db.mongo-cluster" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.document-db.mongo-cluster.yml" + - "avm/res/document-db/mongo-cluster/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/document-db/mongo-cluster" + workflowPath: ".github/workflows/avm.res.document-db.mongo-cluster.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/document-db/mongo-cluster/README.md b/avm/res/document-db/mongo-cluster/README.md new file mode 100644 index 0000000000..c4af03e2b4 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/README.md @@ -0,0 +1,1393 @@ +# Azure Cosmos DB MongoDB vCore cluster `[Microsoft.DocumentDB/mongoClusters]` + +This module deploys a Azure Cosmos DB MongoDB vCore cluster. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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.DocumentDB/mongoClusters` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters) | +| `Microsoft.DocumentDB/mongoClusters/firewallRules` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters/firewallRules) | +| `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) | + +## 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/document-db/mongo-cluster:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Deploying with a key vault reference to save secrets](#example-2-deploying-with-a-key-vault-reference-to-save-secrets) +- [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 mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin001' + administratorLoginPassword: '' + name: 'ddmcdefmin001' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin001" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "ddmcdefmin001" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Deploying with a key vault reference to save secrets_ + +This instance deploys the module saving its secrets in a key vault. + + +

+ +via Bicep module + +```bicep +module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin002' + administratorLoginPassword: '' + name: 'kv-ref' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + location: '' + secretsExportConfiguration: { + connectionStringSecretName: 'connectionString' + keyVaultResourceId: '' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin002" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "kv-ref" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "connectionStringSecretName": "connectionString", + "keyVaultResourceId": "" + } + } + } +} +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with the maximum set of required parameters. + + +

+ +via Bicep module + +```bicep +module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin003' + administratorLoginPassword: '' + name: 'ddmcmax001' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + createMode: 'Default' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + highAvailabilityMode: false + location: '' + networkAcls: { + allowAllIPs: true + allowAzureIPs: true + customRules: [ + { + endIpAddress: '5.6.7.8' + firewallRuleName: 'allow-1.2.3.4-to-5.6.7.8' + startIpAddress: '1.2.3.4' + } + ] + } + nodeType: 'Shard' + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } + ] + roleAssignments: [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin003" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "ddmcmax001" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "createMode": { + "value": "Default" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "highAvailabilityMode": { + "value": false + }, + "location": { + "value": "" + }, + "networkAcls": { + "value": { + "allowAllIPs": true, + "allowAzureIPs": true, + "customRules": [ + { + "endIpAddress": "5.6.7.8", + "firewallRuleName": "allow-1.2.3.4-to-5.6.7.8", + "startIpAddress": "1.2.3.4" + } + ] + } + }, + "nodeType": { + "value": "Shard" + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "" + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "60395919-cfd3-47bf-8349-775ddebb255e", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + } + } +} +``` + +
+

+ +### 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 mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin001' + administratorLoginPassword: '' + name: 'ddmcwaf001' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin001" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "ddmcwaf001" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`administratorLogin`](#parameter-administratorlogin) | string | Username for admin user. | +| [`administratorLoginPassword`](#parameter-administratorloginpassword) | securestring | Password for admin user. | +| [`name`](#parameter-name) | string | Name of the Azure Cosmos DB MongoDB vCore cluster. | +| [`nodeCount`](#parameter-nodecount) | int | Number of nodes in the node group. | +| [`sku`](#parameter-sku) | string | SKU defines the CPU and memory that is provisioned for each node. | +| [`storage`](#parameter-storage) | int | Disk storage size for the node group in GB. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`createMode`](#parameter-createmode) | string | Mode to create the azure cosmos db mongodb vCore cluster. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`highAvailabilityMode`](#parameter-highavailabilitymode) | bool | Whether high availability is enabled on the node group. | +| [`location`](#parameter-location) | string | Default to current resource group scope location. Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`networkAcls`](#parameter-networkacls) | object | IP addresses to allow access to the cluster from. | +| [`nodeType`](#parameter-nodetype) | string | Deployed Node type in the node group. | +| [`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. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | +| [`tags`](#parameter-tags) | object | Tags of the Database Account resource. | + +### Parameter: `administratorLogin` + +Username for admin user. + +- Required: Yes +- Type: string + +### Parameter: `administratorLoginPassword` + +Password for admin user. + +- Required: Yes +- Type: securestring + +### Parameter: `name` + +Name of the Azure Cosmos DB MongoDB vCore cluster. + +- Required: Yes +- Type: string + +### Parameter: `nodeCount` + +Number of nodes in the node group. + +- Required: Yes +- Type: int + +### Parameter: `sku` + +SKU defines the CPU and memory that is provisioned for each node. + +- Required: Yes +- Type: string + +### Parameter: `storage` + +Disk storage size for the node group in GB. + +- Required: Yes +- Type: int + +### Parameter: `createMode` + +Mode to create the azure cosmos db mongodb vCore cluster. + +- 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 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: `highAvailabilityMode` + +Whether high availability is enabled on the node group. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Default to current resource group scope 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` + +IP addresses to allow access to the cluster from. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowAllIPs`](#parameter-networkaclsallowallips) | bool | Indicates whether to allow all IP addresses. | +| [`allowAzureIPs`](#parameter-networkaclsallowazureips) | bool | Indicates whether to allow all Azure internal IP addresses. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customRules`](#parameter-networkaclscustomrules) | array | List of custom firewall rules. | + +### Parameter: `networkAcls.allowAllIPs` + +Indicates whether to allow all IP addresses. + +- Required: Yes +- Type: bool + +### Parameter: `networkAcls.allowAzureIPs` + +Indicates whether to allow all Azure internal IP addresses. + +- Required: Yes +- Type: bool + +### Parameter: `networkAcls.customRules` + +List of custom firewall rules. + +- Required: No +- Type: array + +### Parameter: `nodeType` + +Deployed Node type in the node group. + +- Required: No +- Type: string +- Default: `'Shard'` + +### 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. | +| [`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 | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint ip address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private ip addresses of the private endpoint. | + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +Fqdn that resolves to private endpoint ip address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private ip addresses of the private endpoint. + +- Required: Yes +- Type: array + +### 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: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'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: `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 resource ID of the key vault where to store the secrets of this module. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`connectionStringSecretName`](#parameter-secretsexportconfigurationconnectionstringsecretname) | string | The name to use when creating the primary write connection string secret. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The resource ID of the key vault where to store the secrets of this module. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.connectionStringSecretName` + +The name to use when creating the primary write connection string secret. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags of the Database Account resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `connectionStringKey` | string | The connection string key of the mongo cluster. | +| `exportedSecrets` | | The references to the secrets exported to the provided Key Vault. | +| `firewallRules` | array | The name and resource ID of firewall rule. | +| `mongoClusterResourceId` | string | The resource ID of the Azure Cosmos DB MongoDB vCore cluster. | +| `name` | string | The name of the Azure Cosmos DB MongoDB vCore cluster. | +| `privateEndpoints` | array | The private endpoints of the database account. | +| `resourceGroupName` | string | The name of the resource group the firewall rule was created in. | +| `resourceId` | string | The resource ID of the resource group the firewall rule was created in. | + +## 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/res/document-db/mongo-cluster/firewall-rule/README.md b/avm/res/document-db/mongo-cluster/firewall-rule/README.md new file mode 100644 index 0000000000..c60b28b7db --- /dev/null +++ b/avm/res/document-db/mongo-cluster/firewall-rule/README.md @@ -0,0 +1,67 @@ +# Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules `[Microsoft.DocumentDB/mongoClusters/firewallRules]` + +This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.DocumentDB/mongoClusters/firewallRules` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters/firewallRules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endIpAddress`](#parameter-endipaddress) | string | The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. | +| [`name`](#parameter-name) | string | The name of the firewall rule. | +| [`startIpAddress`](#parameter-startipaddress) | string | The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`mongoClusterName`](#parameter-mongoclustername) | string | The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment. | + +### Parameter: `endIpAddress` + +The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the firewall rule. + +- Required: Yes +- Type: string + +### Parameter: `startIpAddress` + +The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. + +- Required: Yes +- Type: string + +### Parameter: `mongoClusterName` + +The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the firewall rule. | +| `resourceGroupName` | string | The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in. | +| `resourceId` | string | The resource ID of the firewall rule. | diff --git a/avm/res/document-db/mongo-cluster/firewall-rule/main.bicep b/avm/res/document-db/mongo-cluster/firewall-rule/main.bicep new file mode 100644 index 0000000000..38ea336d6b --- /dev/null +++ b/avm/res/document-db/mongo-cluster/firewall-rule/main.bicep @@ -0,0 +1,37 @@ +metadata name = 'Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules' +metadata description = 'This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster.' +metadata owner = 'Azure/module-maintainers' + +@description('Conditional. The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment.') +param mongoClusterName string + +@description('Required. The name of the firewall rule.') +param name string + +@description('Required. The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format.') +param startIpAddress string + +@description('Required. The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format.') +param endIpAddress string + +resource mongoCluster 'Microsoft.DocumentDB/mongoClusters@2024-02-15-preview' existing = { + name: mongoClusterName +} + +resource firewallRule 'Microsoft.DocumentDB/mongoClusters/firewallRules@2024-02-15-preview' = { + name: name + parent: mongoCluster + properties: { + startIpAddress: startIpAddress + endIpAddress: endIpAddress + } +} + +@description('The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the firewall rule.') +output name string = firewallRule.name + +@description('The resource ID of the firewall rule.') +output resourceId string = firewallRule.id diff --git a/avm/res/document-db/mongo-cluster/firewall-rule/main.json b/avm/res/document-db/mongo-cluster/firewall-rule/main.json new file mode 100644 index 0000000000..227ec11c2e --- /dev/null +++ b/avm/res/document-db/mongo-cluster/firewall-rule/main.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.27.1.19265", + "templateHash": "11076682219298980277" + }, + "name": "Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules", + "description": "This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "mongoClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the firewall rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/mongoClusters/firewallRules", + "apiVersion": "2024-02-15-preview", + "name": "[format('{0}/{1}', parameters('mongoClusterName'), parameters('name'))]", + "properties": { + "startIpAddress": "[parameters('startIpAddress')]", + "endIpAddress": "[parameters('endIpAddress')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the firewall rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the firewall rule." + }, + "value": "[resourceId('Microsoft.DocumentDB/mongoClusters/firewallRules', parameters('mongoClusterName'), parameters('name'))]" + } + } +} \ No newline at end of file diff --git a/avm/res/document-db/mongo-cluster/main.bicep b/avm/res/document-db/mongo-cluster/main.bicep new file mode 100644 index 0000000000..d4612a2a44 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/main.bicep @@ -0,0 +1,535 @@ +metadata name = 'Azure Cosmos DB MongoDB vCore cluster' +metadata description = '''This module deploys a Azure Cosmos DB MongoDB vCore cluster. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the Azure Cosmos DB MongoDB vCore cluster.') +param name string + +@description('Optional. Default to current resource group scope location. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the Database Account resource.') +param tags object? + +@description('Required. Username for admin user.') +param administratorLogin string + +@secure() +@description('Required. Password for admin user.') +@minLength(8) +@maxLength(128) +param administratorLoginPassword string + +@description('Optional. Mode to create the azure cosmos db mongodb vCore cluster.') +param createMode string = 'Default' + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Whether high availability is enabled on the node group.') +param highAvailabilityMode bool = false + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. IP addresses to allow access to the cluster from.') +param networkAcls networkAclsType? + +@description('Required. Number of nodes in the node group.') +param nodeCount int + +@description('Optional. Deployed Node type in the node group.') +param nodeType string = 'Shard' + +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +@description('Required. SKU defines the CPU and memory that is provisioned for each node.') +param sku string + +@description('Required. Disk storage size for the node group in GB.') +param storage int + +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 (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var firewallRules = union( + map(networkAcls.?customRules ?? [], customRule => { + name: customRule.?firewallRuleName ?? 'allow-${replace(customRule.startIpAddress, '.', '')}-to-${replace(customRule.endIpAddress, '.', '')}' + startIpAddress: customRule.startIpAddress + endIpAddress: customRule.endIpAddress + }), + networkAcls.?allowAllIPs ?? false + ? [ + { + name: 'allow-all-IPs' + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } + ] + : [], + networkAcls.?allowAzureIPs ?? false + ? [ + { + name: 'allow-all-azure-internal-IPs' + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + ] + : [] +) + +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.documentdb-mongocluster.${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 mongoCluster 'Microsoft.DocumentDB/mongoClusters@2024-02-15-preview' = { + name: name + tags: tags + location: location + properties: { + administratorLogin: administratorLogin + administratorLoginPassword: administratorLoginPassword + createMode: createMode + nodeGroupSpecs: [ + { + diskSizeGB: storage + enableHa: highAvailabilityMode + kind: nodeType + nodeCount: nodeCount + sku: sku + } + ] + } +} + +resource mongoCluster_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: mongoCluster + } +] + +resource mongoCluster_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(mongoCluster.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: mongoCluster + } +] + +module mongoCluster_configFireWallRules 'firewall-rule/main.bicep' = [ + for (firewallRule, index) in firewallRules: { + name: '${uniqueString(deployment().name, location)}-firewallRule-${index}' + params: { + mongoClusterName: mongoCluster.name + name: firewallRule.name + startIpAddress: firewallRule.startIpAddress + endIpAddress: firewallRule.endIpAddress + } + } +] + +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!, 'connectionStringSecretName') + ? [ + { + name: secretsExportConfiguration!.connectionStringSecretName + value: mongoCluster.properties.connectionString + } + ] + : [] + ) + } +} + +module mongoCluster_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-databaseAccount-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(mongoCluster.id, '/'))}-${privateEndpoint.?service ?? 'mongoCluster'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(mongoCluster.id, '/'))}-${privateEndpoint.?service ?? 'mongoCluster'}-${index}' + properties: { + privateLinkServiceId: mongoCluster.id + groupIds: [ + privateEndpoint.?service ?? 'mongoCluster' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(mongoCluster.id, '/'))}-${privateEndpoint.?service ?? 'mongoCluster'}-${index}' + properties: { + privateLinkServiceId: mongoCluster.id + groupIds: [ + privateEndpoint.?service ?? 'mongoCluster' + ] + 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 + } + } +] + +@description('The name of the Azure Cosmos DB MongoDB vCore cluster.') +output name string = mongoCluster.name + +@description('The resource ID of the Azure Cosmos DB MongoDB vCore cluster.') +output mongoClusterResourceId string = mongoCluster.id + +@description('The resource ID of the resource group the firewall rule was created in.') +output resourceId string = resourceGroup().id + +@description('The name of the resource group the firewall rule was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The connection string key of the mongo cluster.') +output connectionStringKey string = mongoCluster.properties.connectionString + +@description('The name and resource ID of firewall rule.') +output firewallRules firewallSetType[] = [ + for index in range(0, length(firewallRules ?? [])): { + name: mongoCluster_configFireWallRules[index].outputs.name + resourceId: mongoCluster_configFireWallRules[index].outputs.resourceId + } +] + +@description('The private endpoints of the database account.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: mongoCluster_privateEndpoints[i].outputs.name + resourceId: mongoCluster_privateEndpoints[i].outputs.resourceId + groupId: mongoCluster_privateEndpoints[i].outputs.groupId + customDnsConfig: mongoCluster_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: mongoCluster_privateEndpoints[i].outputs.networkInterfaceIds + } +] + +@description('The references to the secrets exported to the provided Key Vault.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + +// =============== // +// 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 firewallSetType = { + @description('The name of the created firewall rule.') + name: string + + @description('The resource ID of the created firewall rule.') + resourceId: string +} + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type networkAclsType = { + @description('Optional. List of custom firewall rules.') + customRules: [ + { + @description('Optional. The name of the custom firewall rule.') + firewallRuleName: string? + + @description('Required. The starting IP address for the custom firewall rule.') + startIpAddress: string + + @description('Required. The ending IP address for the custom firewall rule.') + endIpAddress: string + } + ]? + + @description('Required. Indicates whether to allow all IP addresses.') + allowAllIPs: bool + + @description('Required. Indicates whether to allow all Azure internal IP addresses.') + allowAzureIPs: bool +} + +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('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') + 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('Required. 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 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 secretsExportConfigurationType = { + @description('Required. The resource ID of the key vault where to store the secrets of this module.') + keyVaultResourceId: string + + @description('Optional. The name to use when creating the primary write connection string secret.') + connectionStringSecretName: string? +} + +import { secretSetType } from 'modules/keyVaultExport.bicep' +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/res/document-db/mongo-cluster/main.json b/avm/res/document-db/mongo-cluster/main.json new file mode 100644 index 0000000000..9d963be7d0 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/main.json @@ -0,0 +1,1898 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.27.1.19265", + "templateHash": "289094531739005234" + }, + "name": "Azure Cosmos DB MongoDB vCore cluster", + "description": "This module deploys a Azure Cosmos DB MongoDB vCore cluster.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "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 + }, + "firewallSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the created firewall rule." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the created firewall rule." + } + } + } + }, + "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 + }, + "networkAclsType": { + "type": "object", + "properties": { + "customRules": { + "type": "array", + "prefixItems": [ + { + "type": "object", + "properties": { + "firewallRuleName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the custom firewall rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The starting IP address for the custom firewall rule." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The ending IP address for the custom firewall rule." + } + } + } + } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Optional. List of custom firewall rules." + } + }, + "allowAllIPs": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether to allow all IP addresses." + } + }, + "allowAzureIPs": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether to allow all Azure internal IP addresses." + } + } + } + }, + "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": "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 + }, + "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 + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the key vault where to store the secrets of this module." + } + }, + "connectionStringSecretName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to use when creating the primary write connection string secret." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "secretSetType": { + "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." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Cosmos DB MongoDB vCore cluster." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Default to current resource group scope location. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Database Account resource." + } + }, + "administratorLogin": { + "type": "string", + "metadata": { + "description": "Required. Username for admin user." + } + }, + "administratorLoginPassword": { + "type": "securestring", + "minLength": 8, + "maxLength": 128, + "metadata": { + "description": "Required. Password for admin user." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "metadata": { + "description": "Optional. Mode to create the azure cosmos db mongodb vCore cluster." + } + }, + "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." + } + }, + "highAvailabilityMode": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether high availability is enabled on the node group." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. IP addresses to allow access to the cluster from." + } + }, + "nodeCount": { + "type": "int", + "metadata": { + "description": "Required. Number of nodes in the node group." + } + }, + "nodeType": { + "type": "string", + "defaultValue": "Shard", + "metadata": { + "description": "Optional. Deployed Node type in the node group." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. SKU defines the CPU and memory that is provisioned for each node." + } + }, + "storage": { + "type": "int", + "metadata": { + "description": "Required. Disk storage size for the node group in GB." + } + } + }, + "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "firewallRules": "[union(map(coalesce(tryGet(parameters('networkAcls'), 'customRules'), createArray()), lambda('customRule', createObject('name', coalesce(tryGet(lambdaVariables('customRule'), 'firewallRuleName'), format('allow-{0}-to-{1}', replace(lambdaVariables('customRule').startIpAddress, '.', ''), replace(lambdaVariables('customRule').endIpAddress, '.', ''))), 'startIpAddress', lambdaVariables('customRule').startIpAddress, 'endIpAddress', lambdaVariables('customRule').endIpAddress))), if(coalesce(tryGet(parameters('networkAcls'), 'allowAllIPs'), false()), createArray(createObject('name', 'allow-all-IPs', 'startIpAddress', '0.0.0.0', 'endIpAddress', '255.255.255.255')), createArray()), if(coalesce(tryGet(parameters('networkAcls'), 'allowAzureIPs'), false()), createArray(createObject('name', 'allow-all-azure-internal-IPs', 'startIpAddress', '0.0.0.0', 'endIpAddress', '0.0.0.0')), createArray()))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.documentdb-mongocluster.{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" + } + } + } + } + }, + "mongoCluster": { + "type": "Microsoft.DocumentDB/mongoClusters", + "apiVersion": "2024-02-15-preview", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "administratorLogin": "[parameters('administratorLogin')]", + "administratorLoginPassword": "[parameters('administratorLoginPassword')]", + "createMode": "[parameters('createMode')]", + "nodeGroupSpecs": [ + { + "diskSizeGB": "[parameters('storage')]", + "enableHa": "[parameters('highAvailabilityMode')]", + "kind": "[parameters('nodeType')]", + "nodeCount": "[parameters('nodeCount')]", + "sku": "[parameters('sku')]" + } + ] + } + }, + "mongoCluster_diagnosticSettings": { + "copy": { + "name": "mongoCluster_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DocumentDB/mongoClusters/{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": [ + "mongoCluster" + ] + }, + "mongoCluster_roleAssignments": { + "copy": { + "name": "mongoCluster_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DocumentDB/mongoClusters/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/mongoClusters', 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": [ + "mongoCluster" + ] + }, + "mongoCluster_configFireWallRules": { + "copy": { + "name": "mongoCluster_configFireWallRules", + "count": "[length(variables('firewallRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-firewallRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "mongoClusterName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[variables('firewallRules')[copyIndex()].name]" + }, + "startIpAddress": { + "value": "[variables('firewallRules')[copyIndex()].startIpAddress]" + }, + "endIpAddress": { + "value": "[variables('firewallRules')[copyIndex()].endIpAddress]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.27.1.19265", + "templateHash": "11076682219298980277" + }, + "name": "Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules", + "description": "This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "mongoClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the firewall rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/mongoClusters/firewallRules", + "apiVersion": "2024-02-15-preview", + "name": "[format('{0}/{1}', parameters('mongoClusterName'), parameters('name'))]", + "properties": { + "startIpAddress": "[parameters('startIpAddress')]", + "endIpAddress": "[parameters('endIpAddress')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the firewall rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the firewall rule." + }, + "value": "[resourceId('Microsoft.DocumentDB/mongoClusters/firewallRules', parameters('mongoClusterName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "mongoCluster" + ] + }, + "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'), 'connectionStringSecretName'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionStringSecretName, 'value', reference('mongoCluster').connectionString)), 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.27.1.19265", + "templateHash": "4835482779180953345" + } + }, + "definitions": { + "secretSetType": { + "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." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "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." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets 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]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "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]" + } + } + } + } + } + }, + "dependsOn": [ + "mongoCluster" + ] + }, + "mongoCluster_privateEndpoints": { + "copy": { + "name": "mongoCluster_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-databaseAccount-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.DocumentDB/mongoClusters', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster'), 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.DocumentDB/mongoClusters', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster')))))), 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.DocumentDB/mongoClusters', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster')), '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": [ + "mongoCluster" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Azure Cosmos DB MongoDB vCore cluster." + }, + "value": "[parameters('name')]" + }, + "mongoClusterResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure Cosmos DB MongoDB vCore cluster." + }, + "value": "[resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource group the firewall rule was created in." + }, + "value": "[resourceGroup().id]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the firewall rule was created in." + }, + "value": "[resourceGroup().name]" + }, + "connectionStringKey": { + "type": "string", + "metadata": { + "description": "The connection string key of the mongo cluster." + }, + "value": "[reference('mongoCluster').connectionString]" + }, + "firewallRules": { + "type": "array", + "items": { + "$ref": "#/definitions/firewallSetType" + }, + "metadata": { + "description": "The name and resource ID of firewall rule." + }, + "copy": { + "count": "[length(range(0, length(coalesce(variables('firewallRules'), createArray()))))]", + "input": { + "name": "[reference(format('mongoCluster_configFireWallRules[{0}]', range(0, length(coalesce(variables('firewallRules'), createArray())))[copyIndex()])).outputs.name.value]", + "resourceId": "[reference(format('mongoCluster_configFireWallRules[{0}]', range(0, length(coalesce(variables('firewallRules'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + } + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "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/res/document-db/mongo-cluster/modules/keyVaultExport.bicep b/avm/res/document-db/mongo-cluster/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..1bd329ba99 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/modules/keyVaultExport.bicep @@ -0,0 +1,50 @@ +@description('Required. The name of the Key Vault to set the secrets in.') +param keyVaultName string + +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +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 + } + } +] + +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetType[] = [ + #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 + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string +} + +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/defaults/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..536ed8e984 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,57 @@ +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}-documentdb-mongoclusters-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ddmcdefmin' + +@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_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// ============ // +// 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 + administratorLogin: 'Admin001' + administratorLoginPassword: password + nodeCount: 2 + sku: 'M30' + storage: 256 + } + } +] diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/dependencies.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/dependencies.bicep new file mode 100644 index 0000000000..d3eadbfb8f --- /dev/null +++ b/avm/res/document-db/mongo-cluster/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 resource Id of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/main.test.bicep new file mode 100644 index 0000000000..82a5ecbb26 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/main.test.bicep @@ -0,0 +1,72 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a key vault reference to save secrets' +metadata description = 'This instance deploys the module saving 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}-documentdb.databaseaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dddaskvs' + +@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@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}-kv-ref' + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + connectionStringSecretName: 'connectionString' + } + administratorLogin: 'Admin002' + administratorLoginPassword: password + nodeCount: 2 + sku: 'M30' + storage: 256 + } +} + +// Output usage examples +output specificSecret string = testDeployment.outputs.exportedSecrets.connectionString.secretResourceId +output allEportedSecrets object = testDeployment.outputs.exportedSecrets +output allExportedSecretResourceIds array = map( + items(testDeployment.outputs.exportedSecrets), + item => item.value.secretResourceId +) diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/max/dependencies.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..16d9a64d1b --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/max/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 Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script to create to get the paired region name.') +param pairedRegionScriptName 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${environment().suffixes.acrLoginServer}' + 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 roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${location}-${managedIdentity.id}-Reader-RoleAssignment') + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) // Reader + principalType: 'ServicePrincipal' + } +} + +resource getPairedRegionScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: pairedRegionScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-Location \\"${location}\\"' + scriptContent: loadTextContent('../../../../../../utilities/e2e-template-assets/scripts/Get-PairedRegion.ps1') + } + dependsOn: [ + roleAssignment + ] +} + +@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 name of the paired region.') +output pairedRegionName string = getPairedRegionScript.properties.outputs.pairedRegionName diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/max/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..e8127df0e3 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/max/main.test.bicep @@ -0,0 +1,163 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with the maximum 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}-documentdb-mongoclusters-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ddmcmax' + +@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_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// ============ // +// 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-ds-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + pairedRegionScriptName: 'dep-${namePrefix}-ds-${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 + administratorLogin: 'Admin003' + administratorLoginPassword: password + createMode: 'Default' + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + highAvailabilityMode: false + networkAcls: { + customRules: [ + { + firewallRuleName: 'allow-1.2.3.4-to-5.6.7.8' + endIpAddress: '5.6.7.8' + startIpAddress: '1.2.3.4' + } + ] + allowAzureIPs: true + allowAllIPs: true + } + nodeCount: 2 + nodeType: 'Shard' + privateEndpoints: [ + { + 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' + } + } + { + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + } + ] + roleAssignments: [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + 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: 'M30' + storage: 256 + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/waf-aligned/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..4d098959c8 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/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}-documentdb-mongoclusters-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ddmcwaf' + +@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_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// ============ // +// 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 + administratorLogin: 'Admin001' + administratorLoginPassword: password + nodeCount: 2 + sku: 'M30' + storage: 256 + } + } +] diff --git a/avm/res/document-db/mongo-cluster/version.json b/avm/res/document-db/mongo-cluster/version.json new file mode 100644 index 0000000000..eb30921b0c --- /dev/null +++ b/avm/res/document-db/mongo-cluster/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 From 0589cbe166fd76f6c79db40a93b1e44cc28fda0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= Date: Wed, 2 Oct 2024 20:33:28 +0200 Subject: [PATCH 30/93] feat: update TLS versions to supported values `avm/res/storage/storage-account` (#3391) ## Description - bumps the API Version to 2023-05-01 - added TLS 1.3 - removed TLS 1.0 and 1.1 Closes #3313 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.storage.storage-account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=storage-account-tls-version)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [x] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/storage/storage-account/README.md | 9 ++++----- avm/res/storage/storage-account/main.bicep | 7 +++---- avm/res/storage/storage-account/main.json | 19 +++++++++---------- avm/res/storage/storage-account/version.json | 2 +- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/avm/res/storage/storage-account/README.md b/avm/res/storage/storage-account/README.md index 310335b0d2..8422599676 100644 --- a/avm/res/storage/storage-account/README.md +++ b/avm/res/storage/storage-account/README.md @@ -22,7 +22,7 @@ This module deploys a Storage Account. | `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` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts) | +| `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) | @@ -2255,7 +2255,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = { | [`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. | +| [`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. | @@ -2730,7 +2730,7 @@ The Storage Account ManagementPolicies Rules. ### Parameter: `minimumTlsVersion` -Set the minimum TLS version on request to storage. +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 @@ -2738,9 +2738,8 @@ Set the minimum TLS version on request to storage. - Allowed: ```Bicep [ - 'TLS1_0' - 'TLS1_1' 'TLS1_2' + 'TLS1_3' ] ``` diff --git a/avm/res/storage/storage-account/main.bicep b/avm/res/storage/storage-account/main.bicep index 014c244abc..b8b321d82c 100644 --- a/avm/res/storage/storage-account/main.bicep +++ b/avm/res/storage/storage-account/main.bicep @@ -114,11 +114,10 @@ param tableServices object = {} param allowBlobPublicAccess bool = false @allowed([ - 'TLS1_0' - 'TLS1_1' 'TLS1_2' + 'TLS1_3' ]) -@description('Optional. Set the minimum TLS version on request to storage.') +@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.') @@ -341,7 +340,7 @@ resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentiti ) } -resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = { name: name location: location kind: kind diff --git a/avm/res/storage/storage-account/main.json b/avm/res/storage/storage-account/main.json index 90cce4364c..3f89f10c57 100644 --- a/avm/res/storage/storage-account/main.json +++ b/avm/res/storage/storage-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "6607893452071234065" + "templateHash": "7109049210516898074" }, "name": "Storage Accounts", "description": "This module deploys a Storage Account.", @@ -816,12 +816,11 @@ "type": "string", "defaultValue": "TLS1_2", "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" + "TLS1_2", + "TLS1_3" ], "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." + "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": { @@ -1040,7 +1039,7 @@ }, "storageAccount": { "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", + "apiVersion": "2023-05-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -4906,7 +4905,7 @@ "value": "[last(split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/'))]" }, "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey1, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString1, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[0].value))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey2, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString2, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[1].value))), createArray()))]" + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey1, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString1, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[0].value))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey2, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString2, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[1].value))), createArray()))]" } }, "template": { @@ -5058,14 +5057,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(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', '2022-09-01', 'full').location]" + "value": "[reference('storageAccount', '2023-05-01', 'full').location]" }, "serviceEndpoints": { "type": "object", @@ -5098,4 +5097,4 @@ "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/res/storage/storage-account/version.json b/avm/res/storage/storage-account/version.json index 291fb73e82..35d09f6dbf 100644 --- a/avm/res/storage/storage-account/version.json +++ b/avm/res/storage/storage-account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.13", + "version": "0.14", "pathFilters": [ "./main.json" ] From e549f47b7e6f127c8a5b2eeece5ab364173fb757 Mon Sep 17 00:00:00 2001 From: Kris Baranek <20225789+krbar@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:05:59 +0200 Subject: [PATCH 31/93] feat: New module `avm/res/service-networking/traffic-controller` (#3169) ## Description New Module `avm/res/service-networking/traffic-controller` (Application Gateway for Containers). Related Module Proposal: https://github.com/Azure/Azure-Verified-Modules/issues/712 ## Adding a new module - [x] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [x] I have run deployment tests locally to ensure the module is deployable. ## Pipeline references | Pipeline | | - | | [![avm.res.service-networking.traffic-controller](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.service-networking.traffic-controller.yml/badge.svg?branch=users%2Fkrbar%2FtrafficControllerModule)](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.service-networking.traffic-controller.yml) | --------- Co-authored-by: Alexander Sehr --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + ....service-networking.traffic-controller.yml | 88 ++ .../traffic-controller/README.md | 769 ++++++++++++++++++ .../traffic-controller/association/README.md | 79 ++ .../traffic-controller/association/main.bicep | 51 ++ .../traffic-controller/association/main.json | 85 ++ .../traffic-controller/frontend/README.md | 66 ++ .../traffic-controller/frontend/main.bicep | 43 + .../traffic-controller/frontend/main.json | 74 ++ .../traffic-controller/main.bicep | 301 +++++++ .../traffic-controller/main.json | 742 +++++++++++++++++ .../tests/e2e/defaults/main.test.bicep | 48 ++ .../tests/e2e/max/dependencies.bicep | 49 ++ .../tests/e2e/max/main.test.bicep | 131 +++ .../tests/e2e/waf-aligned/dependencies.bicep | 38 + .../tests/e2e/waf-aligned/main.test.bicep | 98 +++ .../traffic-controller/version.json | 7 + 18 files changed, 2671 insertions(+) create mode 100644 .github/workflows/avm.res.service-networking.traffic-controller.yml create mode 100644 avm/res/service-networking/traffic-controller/README.md create mode 100644 avm/res/service-networking/traffic-controller/association/README.md create mode 100644 avm/res/service-networking/traffic-controller/association/main.bicep create mode 100644 avm/res/service-networking/traffic-controller/association/main.json create mode 100644 avm/res/service-networking/traffic-controller/frontend/README.md create mode 100644 avm/res/service-networking/traffic-controller/frontend/main.bicep create mode 100644 avm/res/service-networking/traffic-controller/frontend/main.json create mode 100644 avm/res/service-networking/traffic-controller/main.bicep create mode 100644 avm/res/service-networking/traffic-controller/main.json create mode 100644 avm/res/service-networking/traffic-controller/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/service-networking/traffic-controller/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/service-networking/traffic-controller/tests/e2e/max/main.test.bicep create mode 100644 avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/service-networking/traffic-controller/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2e2123c29c..400d91ac7a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -147,6 +147,7 @@ /avm/res/search/search-service/ @Azure/avm-res-search-searchservice-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/service-bus/namespace/ @Azure/avm-res-servicebus-namespace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/service-fabric/cluster/ @Azure/avm-res-servicefabric-cluster-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/service-networking/traffic-controller/ @Azure/avm-res-servicenetworking-trafficcontroller-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/signal-r-service/signal-r/ @Azure/avm-res-signalrservice-signalr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/signal-r-service/web-pub-sub/ @Azure/avm-res-signalrservice-webpubsub-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/sql/instance-pool/ @Azure/avm-res-sql-instancepool-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index d9e7855858..f5f78969d2 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -182,6 +182,7 @@ body: - "avm/res/search/search-service" - "avm/res/service-bus/namespace" - "avm/res/service-fabric/cluster" + - "avm/res/service-networking/traffic-controller" - "avm/res/signal-r-service/signal-r" - "avm/res/signal-r-service/web-pub-sub" - "avm/res/sql/instance-pool" diff --git a/.github/workflows/avm.res.service-networking.traffic-controller.yml b/.github/workflows/avm.res.service-networking.traffic-controller.yml new file mode 100644 index 0000000000..775de7a740 --- /dev/null +++ b/.github/workflows/avm.res.service-networking.traffic-controller.yml @@ -0,0 +1,88 @@ +name: "avm.res.service-networking.traffic-controller" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.service-networking.traffic-controller.yml" + - "avm/res/service-networking/traffic-controller/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/service-networking/traffic-controller" + workflowPath: ".github/workflows/avm.res.service-networking.traffic-controller.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/service-networking/traffic-controller/README.md b/avm/res/service-networking/traffic-controller/README.md new file mode 100644 index 0000000000..ce5cb08d93 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/README.md @@ -0,0 +1,769 @@ +# Application Gateway for Containers `[Microsoft.ServiceNetworking/trafficControllers]` + +This module deploys an Application Gateway for Containers + +## 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.ServiceNetworking/trafficControllers` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers) | +| `Microsoft.ServiceNetworking/trafficControllers/associations` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/associations) | +| `Microsoft.ServiceNetworking/trafficControllers/frontends` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/frontends) | + +## 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/service-networking/traffic-controller:`. + +- [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 trafficController 'br/public:avm/res/service-networking/traffic-controller:' = { + name: 'trafficControllerDeployment' + params: { + // Required parameters + name: 'sntcmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

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

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

+ +via Bicep module + +```bicep +module trafficController 'br/public:avm/res/service-networking/traffic-controller:' = { + name: 'trafficControllerDeployment' + params: { + // Required parameters + name: 'sntcmax001' + // Non-required parameters + associations: [ + { + name: 'association1' + subnetResourceId: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'a6931c52-0b79-4fe9-ad3d-72188dfff379' + 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 Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "sntcmax001" + }, + // Non-required parameters + "associations": { + "value": [ + { + "name": "association1", + "subnetResourceId": "" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "frontends": { + "value": [ + { + "name": "frontend1" + }, + { + "name": "frontend2" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "a6931c52-0b79-4fe9-ad3d-72188dfff379", + "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" + } + } + } +} +``` + +
+

+ +### 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 trafficController 'br/public:avm/res/service-networking/traffic-controller:' = { + name: 'trafficControllerDeployment' + params: { + // Required parameters + name: 'sntcwaf001' + // Non-required parameters + associations: [ + { + name: 'association1' + subnetResourceId: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "sntcwaf001" + }, + // Non-required parameters + "associations": { + "value": [ + { + "name": "association1", + "subnetResourceId": "" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "frontends": { + "value": [ + { + "name": "frontend1" + }, + { + "name": "frontend2" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "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 for Containers to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`associations`](#parameter-associations) | array | List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`frontends`](#parameter-frontends) | array | List of Application Gateway for Containers frontends. | +| [`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` + +Name of the Application Gateway for Containers to create. + +- Required: Yes +- Type: string + +### Parameter: `associations` + +List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-associationsname) | string | The name of the Application Gateway for Containers association. | +| [`subnetResourceId`](#parameter-associationssubnetresourceid) | string | The resource ID of the subnet to associate with the Application Gateway for Containers. | + +### Parameter: `associations.name` + +The name of the Application Gateway for Containers association. + +- Required: Yes +- Type: string + +### Parameter: `associations.subnetResourceId` + +The resource ID of the subnet to associate with the Application Gateway for Containers. + +- 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: `frontends` + +List of Application Gateway for Containers frontends. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-frontendsname) | string | The name of the Application Gateway for Containers frontend. | + +### Parameter: `frontends.name` + +The name of the Application Gateway for Containers frontend. + +- 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'` + - `'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 | +| :-- | :-- | :-- | +| `associations` | array | The associations of the Application Gateway for Containers. | +| `configurationEndpoints` | array | The configuration endpoints of the Application Gateway for Containers. | +| `frontends` | array | The frontends of the Application Gateway for Containers. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Application Gateway for Containers. | +| `resourceGroupName` | string | The name of the resource group the resource was created in. | +| `resourceId` | string | The resource ID of the Application Gateway for Containers. | + +## Notes + +> **Limitation**: At this time, the number of associations is limited to 1 (Source: [Application Gateway for Containers associations](https://learn.microsoft.com/en-us/azure/application-gateway/for-containers/application-gateway-for-containers-components#application-gateway-for-containers-associations)) + +## 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/res/service-networking/traffic-controller/association/README.md b/avm/res/service-networking/traffic-controller/association/README.md new file mode 100644 index 0000000000..87488abfe2 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/association/README.md @@ -0,0 +1,79 @@ +# Application Gateway for Containers Association `[Microsoft.ServiceNetworking/trafficControllers/associations]` + +This module deploys an Application Gateway for Containers Association + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.ServiceNetworking/trafficControllers/associations` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/associations) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the association to create. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`trafficControllerName`](#parameter-trafficcontrollername) | string | The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | Location for all Resources. | + +**Reuired parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | The resource ID of the subnet to associate with the traffic controller. | + +### Parameter: `name` + +Name of the association to create. + +- Required: Yes +- Type: string + +### Parameter: `trafficControllerName` + +The name of the parent Application Gateway for Containers instance. 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: `subnetResourceId` + +The resource ID of the subnet to associate with the traffic controller. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the association. | +| `resourceGroupName` | string | The name of the resource group the resource was created in. | +| `resourceId` | string | The resource ID of the association. | +| `subnetResourceId` | string | The resource ID of the associated subnet. | diff --git a/avm/res/service-networking/traffic-controller/association/main.bicep b/avm/res/service-networking/traffic-controller/association/main.bicep new file mode 100644 index 0000000000..70cc047a29 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/association/main.bicep @@ -0,0 +1,51 @@ +metadata name = 'Application Gateway for Containers Association' +metadata description = 'This module deploys an Application Gateway for Containers Association' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the association to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment.') +param trafficControllerName string + +@description('Reuired. The resource ID of the subnet to associate with the traffic controller.') +param subnetResourceId string + +// ============== // +// Resources // +// ============== // + +resource trafficController 'Microsoft.ServiceNetworking/trafficControllers@2023-11-01' existing = { + name: trafficControllerName +} + +resource association 'Microsoft.ServiceNetworking/trafficControllers/associations@2023-11-01' = { + name: name + parent: trafficController + location: location + properties: { + associationType: 'subnets' + subnet: { + id: subnetResourceId + } + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource ID of the association.') +output resourceId string = association.id + +@description('The name of the association.') +output name string = association.name + +@description('The name of the resource group the resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the associated subnet.') +output subnetResourceId string = association.properties.subnet.id diff --git a/avm/res/service-networking/traffic-controller/association/main.json b/avm/res/service-networking/traffic-controller/association/main.json new file mode 100644 index 0000000000..638bc670f4 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/association/main.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "17751059838446450774" + }, + "name": "Application Gateway for Containers Association", + "description": "This module deploys an Application Gateway for Containers Association", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the association to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Reuired. The resource ID of the subnet to associate with the traffic controller." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/associations", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "associationType": "subnets", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the association." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the association." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the associated subnet." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name')), '2023-11-01').subnet.id]" + } + } +} \ No newline at end of file diff --git a/avm/res/service-networking/traffic-controller/frontend/README.md b/avm/res/service-networking/traffic-controller/frontend/README.md new file mode 100644 index 0000000000..c9447a6ba3 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/frontend/README.md @@ -0,0 +1,66 @@ +# Application Gateway for Containers Frontend `[Microsoft.ServiceNetworking/trafficControllers/frontends]` + +This module deploys an Application Gateway for Containers Frontend + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.ServiceNetworking/trafficControllers/frontends` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/frontends) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the frontend to create. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`trafficControllerName`](#parameter-trafficcontrollername) | string | The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | Location for all Resources. | + +### Parameter: `name` + +Name of the frontend to create. + +- Required: Yes +- Type: string + +### Parameter: `trafficControllerName` + +The name of the parent Application Gateway for Containers instance. 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]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `fqdn` | string | The FQDN of the frontend. | +| `name` | string | The name of the frontend. | +| `resourceGroupName` | string | The name of the resource group the resource was created in. | +| `resourceId` | string | The resource ID of the frontend. | diff --git a/avm/res/service-networking/traffic-controller/frontend/main.bicep b/avm/res/service-networking/traffic-controller/frontend/main.bicep new file mode 100644 index 0000000000..973eb532a7 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/frontend/main.bicep @@ -0,0 +1,43 @@ +metadata name = 'Application Gateway for Containers Frontend' +metadata description = 'This module deploys an Application Gateway for Containers Frontend' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the frontend to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment.') +param trafficControllerName string + +// ============== // +// Resources // +// ============== // + +resource trafficController 'Microsoft.ServiceNetworking/trafficControllers@2023-11-01' existing = { + name: trafficControllerName +} + +resource frontend 'Microsoft.ServiceNetworking/trafficControllers/frontends@2023-11-01' = { + name: name + parent: trafficController + location: location + properties: {} +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource ID of the frontend.') +output resourceId string = frontend.id + +@description('The name of the frontend.') +output name string = frontend.name + +@description('The name of the resource group the resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The FQDN of the frontend.') +output fqdn string = frontend.properties.fqdn diff --git a/avm/res/service-networking/traffic-controller/frontend/main.json b/avm/res/service-networking/traffic-controller/frontend/main.json new file mode 100644 index 0000000000..f3fb57ad7e --- /dev/null +++ b/avm/res/service-networking/traffic-controller/frontend/main.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "12093954076612099884" + }, + "name": "Application Gateway for Containers Frontend", + "description": "This module deploys an Application Gateway for Containers Frontend", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the frontend to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/frontends", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the frontend." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the frontend." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the frontend." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name')), '2023-11-01').fqdn]" + } + } +} \ No newline at end of file diff --git a/avm/res/service-networking/traffic-controller/main.bicep b/avm/res/service-networking/traffic-controller/main.bicep new file mode 100644 index 0000000000..2ac083b224 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/main.bicep @@ -0,0 +1,301 @@ +metadata name = 'Application Gateway for Containers' +metadata description = 'This module deploys an Application Gateway for Containers' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the Application Gateway for Containers to create.') +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. Resource tags.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. List of Application Gateway for Containers frontends.') +param frontends frontendType + +@description('Optional. List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1.') +param associations associationType + +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)) + }) +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.servicenetworking-trafficcontroller.${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 trafficController 'Microsoft.ServiceNetworking/trafficControllers@2023-11-01' = { + name: name + location: location + tags: tags + properties: {} +} + +resource trafficController_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: trafficController +} + +resource trafficController_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: trafficController + } +] + +resource trafficController_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + trafficController.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: trafficController + } +] + +module trafficController_frontends 'frontend/main.bicep' = [ + for (frontend, index) in (frontends ?? []): { + name: '${uniqueString(deployment().name, location)}-TrafficController-Frontend-${index}' + params: { + trafficControllerName: trafficController.name + name: frontend.name + location: location + } + } +] + +module trafficController_associations 'association/main.bicep' = [ + for (association, index) in (associations ?? []): { + name: '${uniqueString(deployment().name, location)}-TrafficController-Association-${index}' + params: { + trafficControllerName: trafficController.name + name: association.name + location: location + subnetResourceId: association.subnetResourceId + } + } +] + +// ============ // +// Outputs // +// ============ // + +@description('The resource ID of the Application Gateway for Containers.') +output resourceId string = trafficController.id + +@description('The name of the Application Gateway for Containers.') +output name string = trafficController.name + +@description('The name of the resource group the resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = trafficController.location + +@description('The configuration endpoints of the Application Gateway for Containers.') +output configurationEndpoints string[] = trafficController.properties.configurationEndpoints + +@description('The frontends of the Application Gateway for Containers.') +output frontends array = [ + for (frontend, i) in (!empty(frontends) ? array(frontends) : []): { + name: trafficController_frontends[i].outputs.name + resourceId: trafficController_frontends[i].outputs.resourceId + fqdn: trafficController_frontends[i].outputs.fqdn + } +] + +@description('The associations of the Application Gateway for Containers.') +output associations array = [ + for (association, i) in (!empty(associations) ? array(associations) : []): { + name: trafficController_associations[i].outputs.name + resourceId: trafficController_associations[i].outputs.resourceId + subnetResourceId: trafficController_associations[i].outputs.subnetResourceId + } +] + +// ================ // +// Definitions // +// ================ // + +type frontendType = { + @description('Required. The name of the Application Gateway for Containers frontend.') + name: string +}[]? + +@maxLength(1) +type associationType = { + @description('Required. The name of the Application Gateway for Containers association.') + name: string + + @description('Required. The resource ID of the subnet to associate with the Application Gateway for Containers.') + subnetResourceId: 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 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/res/service-networking/traffic-controller/main.json b/avm/res/service-networking/traffic-controller/main.json new file mode 100644 index 0000000000..aa85cfc38c --- /dev/null +++ b/avm/res/service-networking/traffic-controller/main.json @@ -0,0 +1,742 @@ +{ + "$schema": "https://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": "13555357375349247834" + }, + "name": "Application Gateway for Containers", + "description": "This module deploys an Application Gateway for Containers", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "frontendType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Application Gateway for Containers frontend." + } + } + } + }, + "nullable": true + }, + "associationType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Application Gateway for Containers association." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet to associate with the Application Gateway for Containers." + } + } + } + }, + "nullable": true, + "maxLength": 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." + } + } + }, + "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. Name of the Application Gateway for Containers 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." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "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 service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "frontends": { + "$ref": "#/definitions/frontendType", + "metadata": { + "description": "Optional. List of Application Gateway for Containers frontends." + } + }, + "associations": { + "$ref": "#/definitions/associationType", + "metadata": { + "description": "Optional. List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1." + } + } + }, + "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.servicenetworking-trafficcontroller.{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" + } + } + } + } + }, + "trafficController": { + "type": "Microsoft.ServiceNetworking/trafficControllers", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + }, + "trafficController_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.ServiceNetworking/trafficControllers/{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": [ + "trafficController" + ] + }, + "trafficController_diagnosticSettings": { + "copy": { + "name": "trafficController_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ServiceNetworking/trafficControllers/{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": [ + "trafficController" + ] + }, + "trafficController_roleAssignments": { + "copy": { + "name": "trafficController_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ServiceNetworking/trafficControllers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ServiceNetworking/trafficControllers', 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": [ + "trafficController" + ] + }, + "trafficController_frontends": { + "copy": { + "name": "trafficController_frontends", + "count": "[length(coalesce(parameters('frontends'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-TrafficController-Frontend-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "trafficControllerName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('frontends'), createArray())[copyIndex()].name]" + }, + "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.30.23.60470", + "templateHash": "12093954076612099884" + }, + "name": "Application Gateway for Containers Frontend", + "description": "This module deploys an Application Gateway for Containers Frontend", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the frontend to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/frontends", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the frontend." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the frontend." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the frontend." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name')), '2023-11-01').fqdn]" + } + } + } + }, + "dependsOn": [ + "trafficController" + ] + }, + "trafficController_associations": { + "copy": { + "name": "trafficController_associations", + "count": "[length(coalesce(parameters('associations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-TrafficController-Association-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "trafficControllerName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('associations'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('associations'), createArray())[copyIndex()].subnetResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "17751059838446450774" + }, + "name": "Application Gateway for Containers Association", + "description": "This module deploys an Application Gateway for Containers Association", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the association to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Reuired. The resource ID of the subnet to associate with the traffic controller." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/associations", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "associationType": "subnets", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the association." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the association." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the associated subnet." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name')), '2023-11-01').subnet.id]" + } + } + } + }, + "dependsOn": [ + "trafficController" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Application Gateway for Containers." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Application Gateway for Containers." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('trafficController', '2023-11-01', 'full').location]" + }, + "configurationEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The configuration endpoints of the Application Gateway for Containers." + }, + "value": "[reference('trafficController').configurationEndpoints]" + }, + "frontends": { + "type": "array", + "metadata": { + "description": "The frontends of the Application Gateway for Containers." + }, + "copy": { + "count": "[length(if(not(empty(parameters('frontends'))), array(parameters('frontends')), createArray()))]", + "input": { + "name": "[reference(format('trafficController_frontends[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('trafficController_frontends[{0}]', copyIndex())).outputs.resourceId.value]", + "fqdn": "[reference(format('trafficController_frontends[{0}]', copyIndex())).outputs.fqdn.value]" + } + } + }, + "associations": { + "type": "array", + "metadata": { + "description": "The associations of the Application Gateway for Containers." + }, + "copy": { + "count": "[length(if(not(empty(parameters('associations'))), array(parameters('associations')), createArray()))]", + "input": { + "name": "[reference(format('trafficController_associations[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('trafficController_associations[{0}]', copyIndex())).outputs.resourceId.value]", + "subnetResourceId": "[reference(format('trafficController_associations[{0}]', copyIndex())).outputs.subnetResourceId.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/defaults/main.test.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..3204196c73 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/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}-servicenetworking-trafficcontrollers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sntcmin' + +@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 // +// ============== // + +@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/res/service-networking/traffic-controller/tests/e2e/max/dependencies.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..ee481bbc78 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/tests/e2e/max/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 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, 24, 0) + delegations: [ + { + name: 'Microsoft.ServiceNetworking.trafficControllers' + properties: { + serviceName: 'Microsoft.ServiceNetworking/trafficControllers' + } + } + ] + } + } + ] + } +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created default Virtual Network Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/max/main.test.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..3636eeb929 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/tests/e2e/max/main.test.bicep @@ -0,0 +1,131 @@ +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}-servicenetworking-trafficcontrollers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sntcmax' + +@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}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 + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + associations: [ + { + name: 'association1' + subnetResourceId: nestedDependencies.outputs.defaultSubnetResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'a6931c52-0b79-4fe9-ad3d-72188dfff379' + 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 + } + ] + } + } +] diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..c71e8b7ac8 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/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 Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + delegations: [ + { + name: 'Microsoft.ServiceNetworking.trafficControllers' + properties: { + serviceName: 'Microsoft.ServiceNetworking/trafficControllers' + } + } + ] + } + } + ] + } +} + +@description('The resource ID of the created default Virtual Network Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/main.test.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..499b6a760a --- /dev/null +++ b/avm/res/service-networking/traffic-controller/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}-servicenetworking-trafficcontrollers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sntcwaf' + +@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 + 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}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 + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + associations: [ + { + name: 'association1' + subnetResourceId: nestedDependencies.outputs.defaultSubnetResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + } +] diff --git a/avm/res/service-networking/traffic-controller/version.json b/avm/res/service-networking/traffic-controller/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/service-networking/traffic-controller/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From bea4f7ee5cd8e05c00829f989ec443f3a39f9ce5 Mon Sep 17 00:00:00 2001 From: "Axel B. Andersen" Date: Thu, 3 Oct 2024 10:15:27 +0200 Subject: [PATCH 32/93] fix: isHnsEnabled - `avm/res/storage/storage-account` (#3317) ## Description Fix Cannot redeploy if EnableHierargicalNamespace is false Fixes #1522 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.storage.storage-account](https://github.com/Agazoth/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=Agazoth%2FFixRedeployWithisHnsEnabled)](https://github.com/Agazoth/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/storage/storage-account/main.bicep | 2 +- avm/res/storage/storage-account/main.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/avm/res/storage/storage-account/main.bicep b/avm/res/storage/storage-account/main.bicep index b8b321d82c..8e491ac177 100644 --- a/avm/res/storage/storage-account/main.bicep +++ b/avm/res/storage/storage-account/main.bicep @@ -412,7 +412,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = { } : null supportsHttpsTrafficOnly: supportsHttpsTrafficOnly - isHnsEnabled: enableHierarchicalNamespace ? enableHierarchicalNamespace : null + isHnsEnabled: enableHierarchicalNamespace isSftpEnabled: enableSftp isNfsV3Enabled: enableNfsV3 ? enableNfsV3 : any('') largeFileSharesState: (skuName == 'Standard_LRS') || (skuName == 'Standard_ZRS') ? largeFileSharesState : null diff --git a/avm/res/storage/storage-account/main.json b/avm/res/storage/storage-account/main.json index 3f89f10c57..b6d1cc5d74 100644 --- a/avm/res/storage/storage-account/main.json +++ b/avm/res/storage/storage-account/main.json @@ -1063,7 +1063,7 @@ "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())]", + "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())]", From 7ff2e41d2ea4cd91f7b3d31783b2268eb2e2f2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= Date: Fri, 4 Oct 2024 15:33:08 +0200 Subject: [PATCH 33/93] feat: adds Bicep parameters file examples (#3375) ## Description In addition to the existing Bicep and Json examples, add Bicep parameters file examples. ![image](https://github.com/user-attachments/assets/c27a2c20-1243-4602-ada7-1beadeda202d) Closes #3374 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.ptn.aca-lza.hosting-environment](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.aca-lza.hosting-environment.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.aca-lza.hosting-environment.yml) [![avm.res.ptn.ai-platform.baseline](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml) [![avm.res.ptn.authorization.policy-assignment](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml) [![avm.res.ptn.authorization.resource-role-assignment](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml) [![avm.res.ptn.authorization.role-assignment](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml) [![avm.res.ptn.azd.apim-api](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.azd.apim-api.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.azd.apim-api.yml) [![avm.res.ptn.azd.container-apps](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-apps.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-apps.yml) [![avm.res.ptn.azd.insights-dashboard](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.azd.insights-dashboard.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.azd.insights-dashboard.yml) [![avm.res.ptn.deployment-script.import-image-to-acr](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml) [![avm.res.ptn.dev-ops.cicd-agents-and-runners](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.dev-ops.cicd-agents-and-runners.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.dev-ops.cicd-agents-and-runners.yml) [![avm.res.ptn.finops-toolkit.finops-hub](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.finops-toolkit.finops-hub.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.finops-toolkit.finops-hub.yml) [![avm.res.ptn.lz.sub-vending](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml) [![avm.res.ptn.network.hub-networking](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.network.hub-networking.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.network.hub-networking.yml) [![avm.res.ptn.network.private-link-private-dns-zones](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.network.private-link-private-dns-zones.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.network.private-link-private-dns-zones.yml) [![avm.res.ptn.policy-insights.remediation](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml) [![avm.res.ptn.security.security-center](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml) [![avm.res.ptn.virtual-machine-images.azure-image-builder](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml) [![avm.res.aad.domain-service](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml) [![avm.res.alerts-management.action-rule](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.alerts-management.action-rule.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.alerts-management.action-rule.yml) [![avm.res.analysis-services.server](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml) [![avm.res.api-management.service](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml) [![avm.res.app-configuration.configuration-store](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml) [![avm.res.app.container-app](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml) [![avm.res.app.job](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.job.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.job.yml) [![avm.res.app.managed-environment](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml) [![avm.res.automation.automation-account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml) [![avm.res.batch.batch-account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml) [![avm.res.cache.redis](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml) [![avm.res.cdn.profile](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml) [![avm.res.cognitive-services.account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) [![avm.res.communication.communication-service](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml) [![avm.res.communication.email-service](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml) [![avm.res.compute.availability-set](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml) [![avm.res.compute.disk-encryption-set](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml) [![avm.res.compute.disk](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml) [![avm.res.compute.gallery](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml) [![avm.res.compute.image](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml) [![avm.res.compute.proximity-placement-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml) [![avm.res.compute.ssh-public-key](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml) [![avm.res.compute.virtual-machine-scale-set](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml) [![avm.res.compute.virtual-machine](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml) [![avm.res.consumption.budget](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml) [![avm.res.container-instance.container-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml) [![avm.res.container-registry.registry](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml) [![avm.res.container-service.managed-cluster](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml) (unrelated, WAF) [![avm.res.data-factory.factory](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml) [![avm.res.data-protection.backup-vault](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml) [![avm.res.databricks.access-connector](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml) [![avm.res.databricks.workspace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml) [![avm.res.db-for-my-sql.flexible-server](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml) [![avm.res.db-for-postgre-sql.flexible-server](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml) [![avm.res.desktop-virtualization.application-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml) [![avm.res.desktop-virtualization.host-pool](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml) [![avm.res.desktop-virtualization.scaling-plan](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml) [![avm.res.desktop-virtualization.workspace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml) [![avm.res.dev-ops-infrastructure.pool](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml) [![avm.res.dev-test-lab.lab](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml) (unrelaged, module broken) [![avm.res.digital-twins.digital-twins-instance](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml) [![avm.res.document-db.database-account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml) [![avm.res.document-db.mongo-cluster](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.document-db.mongo-cluster.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.document-db.mongo-cluster.yml) [![avm.res.event-grid.domain](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml) [![avm.res.event-grid.namespace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml) [![avm.res.event-grid.system-topic](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml) [![avm.res.event-grid.topic](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml) [![avm.res.event-hub.namespace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml) [![avm.res.health-bot.health-bot](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml) [![avm.res.healthcare-apis.workspace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml) [![avm.res.hybrid-compute.machine](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.hybrid-compute.machine.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.hybrid-compute.machine.yml) [![avm.res.insights.action-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml) [![avm.res.insights.activity-log-alert](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml) [![avm.res.insights.component](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml) [![avm.res.insights.data-collection-endpoint](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml) [![avm.res.insights.data-collection-rule](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml) [![avm.res.insights.diagnostic-setting](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml) [![avm.res.insights.metric-alert](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml) [![avm.res.insights.private-link-scope](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml) [![avm.res.insights.scheduled-query-rule](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml) [![avm.res.insights.webtest](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml) [![avm.res.key-vault.vault](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) [![avm.res.kubernetes-configuration.extension](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml) [![avm.res.kubernetes-configuration.flux-configuration](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml) [![avm.res.kusto.cluster](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.kusto.cluster.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.kusto.cluster.yml) [![avm.res.load-test-service.load-test](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml) [![avm.res.logic.workflow](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml) [![avm.res.machine-learning-services.workspace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml) [![avm.res.maintenance.maintenance-configuration](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml) [![avm.res.managed-identity.user-assigned-identity](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml) [![avm.res.managed-services.registration-definition](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml) [![avm.res.management.management-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml) [![avm.res.net-app.net-app-account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml) [![avm.res.network.application-gateway-web-application-firewall-policy](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml) [![avm.res.network.application-gateway](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml) [![avm.res.network.application-security-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml) [![avm.res.network.azure-firewall](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) [![avm.res.network.bastion-host](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml) [![avm.res.network.connection](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml) [![avm.res.network.ddos-protection-plan](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml) [![avm.res.network.dns-forwarding-ruleset](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml) [![avm.res.network.dns-resolver](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml) [![avm.res.network.dns-zone](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml) [![avm.res.network.express-route-circuit](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml) [![avm.res.network.express-route-gateway](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml) [![avm.res.network.firewall-policy](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml) [![avm.res.network.front-door-web-application-firewall-policy](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml) [![avm.res.network.front-door](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml) [![avm.res.network.ip-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml) [![avm.res.network.load-balancer](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml) [![avm.res.network.local-network-gateway](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml) [![avm.res.network.nat-gateway](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml) [![avm.res.network.network-interface](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml) [![avm.res.network.network-manager](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml) [![avm.res.network.network-security-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml) [![avm.res.network.network-watcher](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml) [![avm.res.network.private-dns-zone](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml) [![avm.res.network.private-endpoint](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml) [![avm.res.network.private-link-service](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml) [![avm.res.network.public-ip-address](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml) [![avm.res.network.public-ip-prefix](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml) [![avm.res.network.route-table](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml) [![avm.res.network.service-endpoint-policy](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml) [![avm.res.network.trafficmanagerprofile](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml) [![avm.res.network.virtual-hub](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml) [![avm.res.network.virtual-network-gateway](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml) [![avm.res.network.virtual-network](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) [![avm.res.network.virtual-wan](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml) [![avm.res.network.vpn-gateway](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml) [![avm.res.network.vpn-site](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml) [![avm.res.operational-insights.workspace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml) [![avm.res.operations-management.solution](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml) [![avm.res.portal.dashboard](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.portal.dashboard.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.portal.dashboard.yml) [![avm.res.power-bi-dedicated.capacity](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml) [![avm.res.purview.account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml) [![avm.res.recovery-services.vault](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml) [![avm.res.relay.namespace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml) [![avm.res.resource-graph.query](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml) [![avm.res.resources.deployment-script](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml) [![avm.res.resources.resource-group](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml) [![avm.res.search.search-service](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml) [![avm.res.service-bus.namespace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml) [![avm.res.service-fabric.cluster](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml) [![avm.res.signal-r-service.signal-r](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml) [![avm.res.signal-r-service.web-pub-sub](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml) [![avm.res.sql.instance-pool](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml) [![avm.res.sql.managed-instance](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml) (unrelated, WAF) [![avm.res.sql.server](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml) [![avm.res.storage.storage-account](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) [![avm.res.synapse.private-link-hub](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml) [![avm.res.synapse.workspace](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml) [![avm.res.virtual-machine-images.image-template](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml) [![avm.res.web.connection](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml) [![avm.res.web.hosting-environment](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml) (unrelated, WAF) [![avm.res.web.serverfarm](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml) [![avm.res.web.site](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.site.yml) [![avm.res.web.static-site](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml/badge.svg?branch=doc-bicepparam)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml) | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/ptn/aca-lza/hosting-environment/README.md | 123 +- avm/ptn/ai-platform/baseline/README.md | 227 ++- .../authorization/policy-assignment/README.md | 320 +++- .../resource-role-assignment/README.md | 42 +- .../authorization/role-assignment/README.md | 130 +- avm/ptn/azd/apim-api/README.md | 24 +- avm/ptn/azd/container-apps/README.md | 36 +- avm/ptn/azd/insights-dashboard/README.md | 41 +- .../import-image-to-acr/README.md | 74 +- .../dev-ops/cicd-agents-and-runners/README.md | 321 +++- avm/ptn/finops-toolkit/finops-hub/README.md | 18 +- avm/ptn/lz/sub-vending/README.md | 136 +- avm/ptn/network/hub-networking/README.md | 371 ++++- .../private-link-private-dns-zones/README.md | 54 +- avm/ptn/policy-insights/remediation/README.md | 140 +- avm/ptn/security/security-center/README.md | 65 +- .../azure-image-builder/README.md | 257 +++- avm/res/aad/domain-service/README.md | 61 +- .../alerts-management/action-rule/README.md | 194 ++- avm/res/analysis-services/server/README.md | 159 +- avm/res/api-management/service/README.md | 506 ++++++- .../configuration-store/README.md | 262 +++- avm/res/app/container-app/README.md | 261 +++- avm/res/app/job/README.md | 267 +++- avm/res/app/managed-environment/README.md | 185 ++- .../automation/automation-account/README.md | 497 +++++- avm/res/batch/batch-account/README.md | 268 +++- avm/res/cache/redis/README.md | 270 +++- avm/res/cdn/profile/README.md | 330 +++- avm/res/cognitive-services/account/README.md | 453 +++++- .../communication-service/README.md | 121 +- avm/res/communication/email-service/README.md | 134 +- avm/res/compute/availability-set/README.md | 93 +- avm/res/compute/disk-encryption-set/README.md | 151 +- avm/res/compute/disk/README.md | 155 +- avm/res/compute/gallery/README.md | 282 +++- avm/res/compute/image/README.md | 105 +- .../proximity-placement-group/README.md | 119 +- avm/res/compute/ssh-public-key/README.md | 112 +- .../virtual-machine-scale-set/README.md | 666 +++++++- avm/res/compute/virtual-machine/README.md | 1345 ++++++++++++++++- avm/res/consumption/budget/README.md | 107 +- .../container-group/README.md | 398 ++++- avm/res/container-registry/registry/README.md | 297 +++- .../managed-cluster/README.md | 647 +++++++- avm/res/data-factory/factory/README.md | 211 ++- .../data-protection/backup-vault/README.md | 223 ++- avm/res/databricks/access-connector/README.md | 100 +- avm/res/databricks/workspace/README.md | 242 ++- .../db-for-my-sql/flexible-server/README.md | 221 ++- .../flexible-server/README.md | 318 +++- .../application-group/README.md | 133 +- .../host-pool/README.md | 172 ++- .../scaling-plan/README.md | 227 ++- .../workspace/README.md | 190 ++- avm/res/dev-ops-infrastructure/pool/README.md | 212 ++- .../digital-twins-instance/README.md | 186 ++- .../document-db/database-account/README.md | 999 +++++++++++- avm/res/document-db/mongo-cluster/README.md | 170 ++- avm/res/event-grid/domain/README.md | 177 ++- avm/res/event-grid/namespace/README.md | 591 +++++++- avm/res/event-grid/system-topic/README.md | 174 ++- avm/res/event-grid/topic/README.md | 229 ++- avm/res/event-hub/namespace/README.md | 385 ++++- avm/res/health-bot/health-bot/README.md | 99 +- avm/res/healthcare-apis/workspace/README.md | 188 ++- avm/res/hybrid-compute/machine/README.md | 113 +- avm/res/insights/action-group/README.md | 105 +- avm/res/insights/activity-log-alert/README.md | 193 ++- avm/res/insights/component/README.md | 118 +- .../data-collection-endpoint/README.md | 92 +- .../insights/data-collection-rule/README.md | 874 ++++++++++- avm/res/insights/diagnostic-setting/README.md | 67 +- avm/res/insights/metric-alert/README.md | 135 +- avm/res/insights/private-link-scope/README.md | 335 +++- .../insights/scheduled-query-rule/README.md | 192 ++- avm/res/insights/webtest/README.md | 115 +- avm/res/key-vault/vault/README.md | 471 +++++- .../extension/README.md | 124 +- .../flux-configuration/README.md | 124 +- avm/res/kusto/cluster/README.md | 190 ++- avm/res/load-test-service/load-test/README.md | 120 +- avm/res/logic/workflow/README.md | 191 ++- .../workspace/README.md | 382 ++++- .../maintenance-configuration/README.md | 145 +- .../user-assigned-identity/README.md | 127 +- .../registration-definition/README.md | 133 +- avm/res/management/management-group/README.md | 58 +- avm/res/net-app/net-app-account/README.md | 292 +++- .../README.md | 109 +- avm/res/network/application-gateway/README.md | 968 +++++++++++- .../application-security-group/README.md | 91 +- avm/res/network/azure-firewall/README.md | 497 +++++- avm/res/network/bastion-host/README.md | 179 ++- avm/res/network/connection/README.md | 99 +- .../network/ddos-protection-plan/README.md | 91 +- .../network/dns-forwarding-ruleset/README.md | 119 +- avm/res/network/dns-resolver/README.md | 118 +- avm/res/network/dns-zone/README.md | 368 ++++- .../network/express-route-circuit/README.md | 134 +- .../network/express-route-gateway/README.md | 96 +- avm/res/network/firewall-policy/README.md | 152 +- .../README.md | 213 ++- avm/res/network/front-door/README.md | 369 ++++- avm/res/network/ip-group/README.md | 95 +- avm/res/network/load-balancer/README.md | 504 +++++- .../network/local-network-gateway/README.md | 107 +- avm/res/network/nat-gateway/README.md | 209 ++- avm/res/network/network-interface/README.md | 159 +- avm/res/network/network-manager/README.md | 305 +++- .../network/network-security-group/README.md | 203 ++- avm/res/network/network-watcher/README.md | 214 ++- avm/res/network/private-dns-zone/README.md | 312 +++- avm/res/network/private-endpoint/README.md | 218 ++- .../network/private-link-service/README.md | 166 +- avm/res/network/public-ip-address/README.md | 150 +- avm/res/network/public-ip-prefix/README.md | 94 +- avm/res/network/route-table/README.md | 111 +- .../network/service-endpoint-policy/README.md | 87 +- .../network/trafficmanagerprofile/README.md | 149 +- avm/res/network/virtual-hub/README.md | 171 ++- .../network/virtual-network-gateway/README.md | 607 +++++++- avm/res/network/virtual-network/README.md | 326 +++- avm/res/network/virtual-wan/README.md | 95 +- avm/res/network/vpn-gateway/README.md | 145 +- avm/res/network/vpn-site/README.md | 178 ++- .../operational-insights/workspace/README.md | 762 +++++++++- .../operations-management/solution/README.md | 82 +- avm/res/portal/dashboard/README.md | 307 +++- avm/res/power-bi-dedicated/capacity/README.md | 110 +- avm/res/purview/account/README.md | 293 +++- avm/res/recovery-services/vault/README.md | 855 ++++++++++- avm/res/relay/namespace/README.md | 272 +++- avm/res/resource-graph/query/README.md | 94 +- avm/res/resources/deployment-script/README.md | 266 +++- avm/res/resources/resource-group/README.md | 91 +- avm/res/search/search-service/README.md | 266 +++- avm/res/service-bus/namespace/README.md | 456 +++++- avm/res/service-fabric/cluster/README.md | 382 ++++- .../traffic-controller/README.md | 137 +- avm/res/signal-r-service/signal-r/README.md | 189 ++- .../signal-r-service/web-pub-sub/README.md | 195 ++- avm/res/sql/instance-pool/README.md | 39 +- avm/res/sql/managed-instance/README.md | 302 +++- avm/res/sql/server/README.md | 445 +++++- avm/res/storage/storage-account/README.md | 950 +++++++++++- avm/res/synapse/private-link-hub/README.md | 127 +- avm/res/synapse/workspace/README.md | 336 +++- .../image-template/README.md | 204 ++- avm/res/web/connection/README.md | 99 +- avm/res/web/hosting-environment/README.md | 149 +- avm/res/web/serverfarm/README.md | 126 +- avm/res/web/site/README.md | 882 ++++++++++- avm/res/web/static-site/README.md | 171 ++- .../sharedScripts/Set-ModuleReadMe.ps1 | 46 +- 155 files changed, 37183 insertions(+), 625 deletions(-) diff --git a/avm/ptn/aca-lza/hosting-environment/README.md b/avm/ptn/aca-lza/hosting-environment/README.md index 4754ccdb4d..4dd7f7ba52 100644 --- a/avm/ptn/aca-lza/hosting-environment/README.md +++ b/avm/ptn/aca-lza/hosting-environment/README.md @@ -144,7 +144,7 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -215,6 +215,41 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/aca-lza/hosting-environment:' + +// Required parameters +param applicationGatewayCertificateKeyName = 'appgwcert' +param enableApplicationInsights = true +param enableDaprInstrumentation = false +param spokeApplicationGatewaySubnetAddressPrefix = '10.1.3.0/24' +param spokeInfraSubnetAddressPrefix = '10.1.0.0/23' +param spokePrivateEndpointsSubnetAddressPrefix = '10.1.2.0/27' +param spokeVNetAddressPrefixes = [ + '10.1.0.0/22' +] +param vmAdminPassword = '' +param vmAdminUsername = 'vmadmin' +param vmJumpBoxSubnetAddressPrefix = '10.1.2.32/27' +param vmLinuxSshAuthorizedKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC9QWdPia7CYYWWX/+eRrLKzGtQ+tjelZfDlbHy/Dg98 konstantinospantos@KonstaninossMBP.localdomain' +param vmSize = 'Standard_B1s' +// Non-required parameters +param location = '' +param tags = { + environment: 'test' +} +param vmAuthenticationType = 'sshPublicKey' +param vmJumpboxOSType = 'linux' +param workloadName = '' +``` + +
+

+ ### Example 2: _Using a hub and spoke deployment._ This instance deploys the module including a Hub to peer to. @@ -267,7 +302,7 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -359,6 +394,48 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/aca-lza/hosting-environment:' + +// Required parameters +param applicationGatewayCertificateKeyName = 'appgwcert' +param enableApplicationInsights = true +param enableDaprInstrumentation = false +param spokeApplicationGatewaySubnetAddressPrefix = '10.1.3.0/24' +param spokeInfraSubnetAddressPrefix = '10.1.0.0/23' +param spokePrivateEndpointsSubnetAddressPrefix = '10.1.2.0/27' +param spokeVNetAddressPrefixes = [ + '10.1.0.0/22' +] +param vmAdminPassword = '' +param vmAdminUsername = 'vmadmin' +param vmJumpBoxSubnetAddressPrefix = '10.1.2.32/27' +param vmLinuxSshAuthorizedKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC9QWdPia7CYYWWX/+eRrLKzGtQ+tjelZfDlbHy/Dg98 konstantinospantos@KonstaninossMBP.localdomain' +param vmSize = 'Standard_B1s' +// Non-required parameters +param deployZoneRedundantResources = true +param enableDdosProtection = true +param environment = 'dev' +param exposeContainerAppsWith = 'applicationGateway' +param hubVirtualNetworkResourceId = '' +param location = '' +param networkApplianceIpAddress = '' +param storageAccountType = 'Premium_LRS' +param tags = { + environment: 'test' +} +param vmAuthenticationType = 'sshPublicKey' +param vmJumpboxOSType = 'linux' +param workloadName = '' +``` + +
+

+ ### Example 3: _Using all the available options in WAF aligned values._ This instance deploys the module with the all the available parameters in WAF aligned values. @@ -409,7 +486,7 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -495,6 +572,46 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/aca-lza/hosting-environment:' + +// Required parameters +param applicationGatewayCertificateKeyName = 'appgwcert' +param enableApplicationInsights = true +param enableDaprInstrumentation = false +param spokeApplicationGatewaySubnetAddressPrefix = '10.1.3.0/24' +param spokeInfraSubnetAddressPrefix = '10.1.0.0/23' +param spokePrivateEndpointsSubnetAddressPrefix = '10.1.2.0/27' +param spokeVNetAddressPrefixes = [ + '10.1.0.0/22' +] +param vmAdminPassword = '' +param vmAdminUsername = 'vmadmin' +param vmJumpBoxSubnetAddressPrefix = '10.1.2.32/27' +param vmLinuxSshAuthorizedKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC9QWdPia7CYYWWX/+eRrLKzGtQ+tjelZfDlbHy/Dg98 konstantinospantos@KonstaninossMBP.localdomain' +param vmSize = 'Standard_B1s' +// Non-required parameters +param deployZoneRedundantResources = true +param enableDdosProtection = true +param environment = 'dev' +param exposeContainerAppsWith = 'applicationGateway' +param location = '' +param storageAccountType = 'Premium_LRS' +param tags = { + environment: 'test' +} +param vmAuthenticationType = 'sshPublicKey' +param vmJumpboxOSType = 'linux' +param workloadName = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/ai-platform/baseline/README.md b/avm/ptn/ai-platform/baseline/README.md index 709ebd90fe..7676df01c3 100644 --- a/avm/ptn/ai-platform/baseline/README.md +++ b/avm/ptn/ai-platform/baseline/README.md @@ -117,7 +117,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -142,6 +142,25 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param virtualMachineConfiguration = { + adminPassword: '' + adminUsername: 'localAdminUser' +} +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -269,7 +288,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -410,6 +429,123 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = 'aipbmax' +// Non-required parameters +param applicationInsightsConfiguration = { + name: 'appi-aipbmax' +} +param bastionConfiguration = { + disableCopyPaste: true + enabled: true + enableFileCopy: true + enableIpConnect: true + enableKerberos: true + enableShareableLink: true + name: 'bas-aipbmax' + networkSecurityGroupResourceId: '' + scaleUnits: 3 + sku: 'Standard' + subnetAddressPrefix: '10.1.1.0/26' +} +param containerRegistryConfiguration = { + name: 'craipbmax' + trustPolicyStatus: 'disabled' +} +param keyVaultConfiguration = { + enablePurgeProtection: false + name: '' +} +param logAnalyticsConfiguration = { + name: 'log-aipbmax' +} +param managedIdentityName = '' +param storageAccountConfiguration = { + allowSharedKeyAccess: true + name: 'staipbmax' + sku: 'Standard_GRS' +} +param virtualMachineConfiguration = { + adminPassword: '' + adminUsername: 'localAdminUser' + enableAadLoginExtension: true + enableAzureMonitorAgent: true + enabled: true + encryptionAtHost: false + imageReference: { + offer: 'dsvm-win-2022' + publisher: 'microsoft-dsvm' + sku: 'winserver-2022' + version: 'latest' + } + maintenanceConfigurationResourceId: '' + name: '' + nicConfigurationConfiguration: { + ipConfigName: 'ipcfg-aipbmax' + name: 'nic-aipbmax' + networkSecurityGroupResourceId: '' + privateIPAllocationMethod: 'Dynamic' + } + osDisk: { + caching: 'ReadOnly' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 256 + managedDisk: { + storageAccountType: 'Standard_LRS' + } + name: 'disk-aipbmax' + } + patchMode: 'AutomaticByPlatform' + size: 'Standard_DS1_v2' + zone: 0 +} +param virtualNetworkConfiguration = { + addressPrefix: '10.1.0.0/16' + enabled: true + name: 'vnet-aipbmax' + subnet: { + addressPrefix: '10.1.0.0/24' + name: 'snet-aipbmax' + networkSecurityGroupResourceId: '' + } +} +param workspaceConfiguration = { + computes: [ + { + computeType: 'ComputeInstance' + description: 'Default' + location: '' + name: '' + properties: { + vmSize: 'STANDARD_DS11_V2' + } + sku: 'Standard' + } + ] + name: 'hub-aipbmax' + networkIsolationMode: 'AllowOnlyApprovedOutbound' + networkOutboundRules: { + rule1: { + category: 'UserDefined' + destination: 'pypi.org' + type: 'FQDN' + } + } + projectName: 'project-aipbmax' +} +``` + +
+

+ ### Example 3: _Without virtual machine_ This instance deploys the module with a virtual network, but no virtual machine or Azure Bastion host. @@ -441,7 +577,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -470,6 +606,27 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param bastionConfiguration = { + enabled: false +} +param virtualMachineConfiguration = { + enabled: false +} +``` + +
+

+ ### Example 4: _Without virtual network_ This instance deploys the module without a virtual network, virtual machine or Azure Bastion host. @@ -498,7 +655,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -522,6 +679,24 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param virtualNetworkConfiguration = { + enabled: false +} +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -574,7 +749,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -628,6 +803,48 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param managedIdentityName = '' +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param virtualMachineConfiguration = { + adminPassword: '' + adminUsername: 'localAdminUser' + enableAadLoginExtension: true + enableAzureMonitorAgent: true + maintenanceConfigurationResourceId: '' + patchMode: 'AutomaticByPlatform' + zone: 1 +} +param workspaceConfiguration = { + networkIsolationMode: 'AllowOnlyApprovedOutbound' + networkOutboundRules: { + rule: { + category: 'UserDefined' + destination: { + serviceResourceId: '' + subresourceTarget: 'blob' + } + type: 'PrivateEndpoint' + } + } +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/authorization/policy-assignment/README.md b/avm/ptn/authorization/policy-assignment/README.md index a4cb51a7ea..072b3bbe2e 100644 --- a/avm/ptn/authorization/policy-assignment/README.md +++ b/avm/ptn/authorization/policy-assignment/README.md @@ -62,7 +62,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,26 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +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. @@ -182,7 +202,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -294,6 +314,86 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +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 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 = [ + '/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' +] +``` + +
+

+ ### Example 3: _Policy Assignments (Resource Group)_ This module deploys a Policy Assignment at a Resource Group scope using minimal parameters. @@ -326,7 +426,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -362,6 +462,28 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +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. @@ -454,7 +576,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -572,6 +694,88 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +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. @@ -605,7 +809,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -640,6 +844,29 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +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. @@ -731,7 +958,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -846,6 +1073,87 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +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** diff --git a/avm/ptn/authorization/resource-role-assignment/README.md b/avm/ptn/authorization/resource-role-assignment/README.md index 8326536d6c..4e02efebcd 100644 --- a/avm/ptn/authorization/resource-role-assignment/README.md +++ b/avm/ptn/authorization/resource-role-assignment/README.md @@ -55,7 +55,7 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

-via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,26 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

+

+ +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. @@ -117,7 +137,7 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

-via JSON Parameter file +via JSON parameters file ```json { @@ -145,6 +165,24 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

+

+ +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** diff --git a/avm/ptn/authorization/role-assignment/README.md b/avm/ptn/authorization/role-assignment/README.md index 99ebde63c1..b5046b581e 100644 --- a/avm/ptn/authorization/role-assignment/README.md +++ b/avm/ptn/authorization/role-assignment/README.md @@ -59,7 +59,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,24 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +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. @@ -117,7 +135,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -151,6 +169,26 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +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. @@ -181,7 +219,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -215,6 +253,26 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +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. @@ -246,7 +304,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -283,6 +341,27 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +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. @@ -312,7 +391,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -343,6 +422,25 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +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. @@ -373,7 +471,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -407,6 +505,26 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +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** diff --git a/avm/ptn/azd/apim-api/README.md b/avm/ptn/azd/apim-api/README.md index f86fc2befd..a063fabfb7 100644 --- a/avm/ptn/azd/apim-api/README.md +++ b/avm/ptn/azd/apim-api/README.md @@ -63,7 +63,7 @@ module apimApi 'br/public:avm/ptn/azd/apim-api:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -103,6 +103,28 @@ module apimApi 'br/public:avm/ptn/azd/apim-api:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/apim-api:' + +// Required parameters +param apiBackendUrl = '' +param apiDescription = 'api description' +param apiDisplayName = 'apd-aapmin' +param apiName = 'an-aapmin001' +param apiPath = 'apipath-aapmin' +param name = '' +param webFrontendUrl = '' +// Non-required parameters +param location = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/azd/container-apps/README.md b/avm/ptn/azd/container-apps/README.md index 413bf894be..742a2f8be8 100644 --- a/avm/ptn/azd/container-apps/README.md +++ b/avm/ptn/azd/container-apps/README.md @@ -83,7 +83,7 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -145,6 +145,40 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/container-apps:' + +// Required parameters +param containerAppsEnvironmentName = 'acazrcae001' +param containerRegistryName = 'acazrcr001' +param logAnalyticsWorkspaceResourceId = '' +// Non-required parameters +param acrSku = 'Standard' +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetResourceId = '' +param internal = true +param location = '' +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +param zoneRedundant = true +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/azd/insights-dashboard/README.md b/avm/ptn/azd/insights-dashboard/README.md index 92e51c5d57..db6912ad8b 100644 --- a/avm/ptn/azd/insights-dashboard/README.md +++ b/avm/ptn/azd/insights-dashboard/README.md @@ -62,7 +62,7 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,23 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/insights-dashboard:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'aidmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module using large parameters. @@ -117,7 +134,7 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -151,6 +168,26 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/insights-dashboard:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'icmax001' +// Non-required parameters +param applicationType = 'web' +param dashboardName = 'icmaxdb001' +param kind = 'web' +param location = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/deployment-script/import-image-to-acr/README.md b/avm/ptn/deployment-script/import-image-to-acr/README.md index 9015f8760e..0e878635e3 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/README.md +++ b/avm/ptn/deployment-script/import-image-to-acr/README.md @@ -62,7 +62,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

-via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,25 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/deployment-script/import-image-to-acr:' + +// Required parameters +param acrName = '' +param image = 'mcr.microsoft.com/k8se/quickstart-jobs:latest' +param name = 'dsiitamin001' +// Non-required parameters +param location = '' +param overwriteExistingImage = true +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -132,7 +151,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

-via JSON Parameter file +via JSON parameters file ```json { @@ -187,6 +206,35 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/deployment-script/import-image-to-acr:' + +// Required parameters +param acrName = '' +param image = 'mcr.microsoft.com/k8se/quickstart-jobs:latest' +param name = 'dsiitamax001' +// Non-required parameters +param assignRbacRole = true +param cleanupPreference = 'OnExpiration' +param location = '' +param managedIdentities = '' +param newImageName = 'application/your-image-name:tag' +param overwriteExistingImage = true +param storageAccountResourceId = '' +param subnetResourceIds = '' +param tags = { + Env: 'test' + '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. @@ -217,7 +265,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

-via JSON Parameter file +via JSON parameters file ```json { @@ -251,6 +299,26 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/deployment-script/import-image-to-acr:' + +// Required parameters +param acrName = '' +param image = 'mcr.microsoft.com/k8se/quickstart-jobs:latest' +param name = 'dsiitawaf001' +// Non-required parameters +param location = '' +param managedIdentities = '' +param overwriteExistingImage = true +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/dev-ops/cicd-agents-and-runners/README.md b/avm/ptn/dev-ops/cicd-agents-and-runners/README.md index 74b97be263..0b7b19c8fe 100644 --- a/avm/ptn/dev-ops/cicd-agents-and-runners/README.md +++ b/avm/ptn/dev-ops/cicd-agents-and-runners/README.md @@ -67,14 +67,14 @@ This module deploys self-hosted agents and runners for Azure DevOps and GitHub o | `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/storageAccounts/fileServices) | +| `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/storageAccounts/localUsers) | +| `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/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `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 @@ -135,7 +135,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -181,6 +181,38 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-app' + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aca' +} +param selfHostedConfig = { + agentsPoolName: 'agents-pool' + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + selfHostedType: 'azuredevops' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 2: _Using only defaults for Azure DevOps self-hosted agents using Azure Container Instances._ This instance deploys the module with the minimum set of required parameters for Azure DevOps self-hosted agents in Azure Container Instances. @@ -222,7 +254,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -267,6 +299,37 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aci' +} +param selfHostedConfig = { + agentsPoolName: 'aci-pool' + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + selfHostedType: 'azuredevops' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 3: _Using only defaults for GitHub self-hosted runners using Azure Container Apps._ This instance deploys the module with the minimum set of required parameters for GitHub self-hosted runners in Azure Container Apps. @@ -308,7 +371,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -353,6 +416,37 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-app' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aca' +} +param selfHostedConfig = { + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + selfHostedType: 'github' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 4: _Using large parameter set for Azure DevOps self-hosted agents using Azure Container Apps._ This instance deploys the module with most of its features enabled for Azure DevOps self-hosted agents using Azure Container Apps. @@ -405,7 +499,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -461,6 +555,48 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-app' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + containerAppSubnetAddressPrefix: '10.0.1.0/24' + containerAppSubnetName: 'acaSubnet' + networkType: 'createNew' + virtualNetworkName: 'vnet-aca' +} +param selfHostedConfig = { + agentNamePrefix: '' + agentsPoolName: 'aca-pool' + azureContainerAppTarget: { + resources: { + cpu: '1' + memory: '2Gi' + } + } + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + placeHolderAgentName: 'acaPlaceHolderAgent' + selfHostedType: 'azuredevops' + targetPipelinesQueueLength: '1' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 5: _Using large parameter set for GitHub self-hosted runners using Azure Container Instances._ This instance deploys the module with most of its features enabled for GitHub self-hosted runners using Azure Container Instances. @@ -514,7 +650,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -571,6 +707,49 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + containerInstanceSubnetAddressPrefix: '10.0.1.0/24' + containerInstanceSubnetName: 'aci-subnet' + networkType: 'createNew' + virtualNetworkName: 'vnet-aci' +} +param selfHostedConfig = { + azureContainerInstanceTarget: { + cpu: 1 + memoryInGB: 2 + numberOfInstances: 3 + sku: 'Standard' + } + ephemeral: true + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + runnerNamePrefix: '' + runnerScope: 'repo' + selfHostedType: 'github' + targetWorkflowQueueLength: '1' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 6: _Using only defaults for Azure DevOps self-hosted agents using Private networking in an existing vnet._ This instance deploys the module with the minimum set of required parameters Azure DevOps self-hosted agents using Private networking in Azure Container Instances in an existing vnet. @@ -623,7 +802,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -679,6 +858,48 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + computeNetworking: { + computeNetworkType: 'azureContainerInstance' + containerInstanceSubnetName: 'aci-subnet' + } + containerRegistryPrivateDnsZoneResourceId: '' + containerRegistryPrivateEndpointSubnetName: 'acr-subnet' + natGatewayPublicIpAddressResourceId: '' + natGatewayResourceId: '' + networkType: 'useExisting' + virtualNetworkResourceId: '' +} +param selfHostedConfig = { + agentNamePrefix: '' + agentsPoolName: 'aci-pool' + azureContainerInstanceTarget: { + numberOfInstances: 2 + } + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + selfHostedType: 'azuredevops' +} +// Non-required parameters +param location = '' +param privateNetworking = true +``` + +
+

+ ### Example 7: _Using only defaults for GitHub self-hosted runners using Private networking in an existing vnet._ This instance deploys the module with the minimum set of required parameters GitHub self-hosted runners using Private networking in Azure Container Apps in an existing vnet. @@ -730,7 +951,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -785,6 +1006,47 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + computeNetworking: { + computeNetworkType: 'azureContainerApp' + containerAppDeploymentScriptSubnetName: 'aca-ds-subnet' + containerAppSubnetName: 'aca-subnet' + containerInstanceSubnetName: 'aci-subnet' + deploymentScriptPrivateDnsZoneResourceId: '' + } + containerRegistryPrivateDnsZoneResourceId: '' + containerRegistryPrivateEndpointSubnetName: 'acr-subnet' + natGatewayPublicIpAddressResourceId: '' + natGatewayResourceId: '' + networkType: 'useExisting' + virtualNetworkResourceId: '' +} +param selfHostedConfig = { + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + selfHostedType: 'github' +} +// Non-required parameters +param location = '' +param privateNetworking = true +``` + +
+

+ ### Example 8: _Using only defaults for GitHub self-hosted runners using Private networking._ This instance deploys the module with the minimum set of required parameters GitHub self-hosted runners using Private networking in Azure Container Instances. @@ -826,7 +1088,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -871,6 +1133,37 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aci' +} +param selfHostedConfig = { + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + selfHostedType: 'github' +} +// Non-required parameters +param location = '' +param privateNetworking = true +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/finops-toolkit/finops-hub/README.md b/avm/ptn/finops-toolkit/finops-hub/README.md index 8458506c7d..4abb463210 100644 --- a/avm/ptn/finops-toolkit/finops-hub/README.md +++ b/avm/ptn/finops-toolkit/finops-hub/README.md @@ -80,7 +80,7 @@ module finopsHub 'br/public:avm/ptn/finops-toolkit/finops-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -102,6 +102,22 @@ module finopsHub 'br/public:avm/ptn/finops-toolkit/finops-hub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/finops-toolkit/finops-hub:' + +// Required parameters +param hubName = 'finops-hub-finmin' +// Non-required parameters +param location = '' +``` + +
+

+ ## Parameters **Optional parameters** diff --git a/avm/ptn/lz/sub-vending/README.md b/avm/ptn/lz/sub-vending/README.md index d1bea9021b..de4ec1a5d2 100644 --- a/avm/ptn/lz/sub-vending/README.md +++ b/avm/ptn/lz/sub-vending/README.md @@ -91,7 +91,7 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -135,6 +135,30 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/lz/sub-vending:' + +param resourceProviders = {} +param subscriptionAliasEnabled = true +param subscriptionAliasName = '' +param subscriptionBillingScope = '' +param subscriptionDisplayName = '' +param subscriptionManagementGroupAssociationEnabled = true +param subscriptionManagementGroupId = 'bicep-lz-vending-automation-child' +param subscriptionTags = { + namePrefix: '' + serviceShort: '' +} +param subscriptionWorkload = 'Production' +``` + +
+

+ ### Example 2: _Hub and spoke topology._ This instance deploys a subscription with a hub-spoke network topology. @@ -202,7 +226,7 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -315,6 +339,63 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/lz/sub-vending:' + +param deploymentScriptLocation = '' +param deploymentScriptManagedIdentityName = '' +param deploymentScriptName = 'ds-ssahs' +param deploymentScriptNetworkSecurityGroupName = '' +param deploymentScriptResourceGroupName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptVirtualNetworkName = '' +param hubNetworkResourceId = '' +param resourceProviders = { + 'Microsoft.AVS': [ + 'AzureServicesVm' + ] + 'Microsoft.HybridCompute': [ + 'ArcServerPrivateLinkPreview' + ] +} +param roleAssignmentEnabled = true +param roleAssignments = [ + { + definition: '/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7' + principalId: '896b1162-be44-4b28-888a-d01acc1b4271' + relativeScope: '' + } +] +param subscriptionAliasEnabled = true +param subscriptionAliasName = '' +param subscriptionBillingScope = '' +param subscriptionDisplayName = '' +param subscriptionManagementGroupAssociationEnabled = true +param subscriptionManagementGroupId = 'bicep-lz-vending-automation-child' +param subscriptionTags = { + namePrefix: '' + serviceShort: '' +} +param subscriptionWorkload = 'Production' +param virtualNetworkAddressSpace = [ + '10.110.0.0/16' +] +param virtualNetworkEnabled = true +param virtualNetworkLocation = '' +param virtualNetworkName = '' +param virtualNetworkPeeringEnabled = true +param virtualNetworkResourceGroupLockEnabled = false +param virtualNetworkResourceGroupName = '' +param virtualNetworkUseRemoteGateways = false +``` + +
+

+ ### Example 3: _Vwan topology._ This instance deploys a subscription with a vwan network topology. @@ -374,7 +455,7 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -477,6 +558,55 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/lz/sub-vending:' + +param deploymentScriptLocation = '' +param deploymentScriptManagedIdentityName = '' +param deploymentScriptName = 'ds-ssawan' +param deploymentScriptNetworkSecurityGroupName = '' +param deploymentScriptResourceGroupName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptVirtualNetworkName = '' +param hubNetworkResourceId = '' +param resourceProviders = {} +param roleAssignmentEnabled = true +param roleAssignments = [ + { + definition: '/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7' + principalId: '896b1162-be44-4b28-888a-d01acc1b4271' + relativeScope: '' + } +] +param subscriptionAliasEnabled = true +param subscriptionAliasName = '' +param subscriptionBillingScope = '' +param subscriptionDisplayName = '' +param subscriptionManagementGroupAssociationEnabled = true +param subscriptionManagementGroupId = 'bicep-lz-vending-automation-child' +param subscriptionTags = { + namePrefix: '' + serviceShort: '' +} +param subscriptionWorkload = 'Production' +param virtualNetworkAddressSpace = [ + '10.210.0.0/16' +] +param virtualNetworkEnabled = true +param virtualNetworkLocation = '' +param virtualNetworkName = '' +param virtualNetworkPeeringEnabled = true +param virtualNetworkResourceGroupLockEnabled = false +param virtualNetworkResourceGroupName = '' +``` + +
+

+ ## Parameters **Optional parameters** diff --git a/avm/ptn/network/hub-networking/README.md b/avm/ptn/network/hub-networking/README.md index e033907b82..490e420691 100644 --- a/avm/ptn/network/hub-networking/README.md +++ b/avm/ptn/network/hub-networking/README.md @@ -64,7 +64,7 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -81,6 +81,19 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -267,7 +280,7 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -449,6 +462,182 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param hubVirtualNetworks = { + hub1: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub1-waf-pip' + } + threatIntelMode: 'Alert' + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remoteVirtualNetworkName: 'hub2' + useRemoteGateways: false + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + hub2: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub2-waf-pip' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: false + flowTimeoutInMinutes: 10 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub2Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remoteVirtualNetworkName: 'hub1' + useRemoteGateways: false + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } +} +param location = '' +``` + +
+

+ ### Example 3: _No Addons_ This instance deploys the module with no add-ons (Firewall / Bastion) enabled. @@ -535,7 +724,7 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -617,6 +806,82 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param hubVirtualNetworks = { + hub1: { + addressPrefixes: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.6' + '10.0.1.7' + ] + enableAzureFirewall: false + enableBastion: false + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } +} +param location = '' +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -725,7 +990,7 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -829,6 +1094,104 @@ module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param hubVirtualNetworks = { + hub1: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub1PublicIp' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.6' + '10.0.1.7' + ] + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } +} +param location = '' +``` + +
+

+ ## Parameters **Optional parameters** diff --git a/avm/ptn/network/private-link-private-dns-zones/README.md b/avm/ptn/network/private-link-private-dns-zones/README.md index df3015ee11..e5f3e732ba 100644 --- a/avm/ptn/network/private-link-private-dns-zones/README.md +++ b/avm/ptn/network/private-link-private-dns-zones/README.md @@ -63,7 +63,7 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

-via JSON Parameter file +via JSON parameters file ```json { @@ -76,6 +76,19 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/private-link-private-dns-zones:' + + +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -106,7 +119,7 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

-via JSON Parameter file +via JSON parameters file ```json { @@ -134,6 +147,26 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/private-link-private-dns-zones:' + +param location = '' +param privateLinkPrivateDnsZones = [ + 'testpdnszone1.int' + 'testpdnszone2.local' +] +param virtualNetworkResourceIdsToLinkTo = [ + '' +] +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -159,7 +192,7 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

-via JSON Parameter file +via JSON parameters file ```json { @@ -178,6 +211,21 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/private-link-private-dns-zones:' + +param virtualNetworkResourceIdsToLinkTo = [ + '' +] +``` + +
+

+ ## Parameters **Optional parameters** diff --git a/avm/ptn/policy-insights/remediation/README.md b/avm/ptn/policy-insights/remediation/README.md index 34c3caff84..ed8b03e57f 100644 --- a/avm/ptn/policy-insights/remediation/README.md +++ b/avm/ptn/policy-insights/remediation/README.md @@ -59,7 +59,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,24 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

+

+ +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. @@ -119,7 +137,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -159,6 +177,28 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

+

+ +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. @@ -189,7 +229,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -223,6 +263,26 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

+

+ +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. @@ -258,7 +318,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -307,6 +367,31 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

+

+ +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. @@ -336,7 +421,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -367,6 +452,25 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

+

+ +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. @@ -401,7 +505,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -447,6 +551,30 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

+

+ +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** diff --git a/avm/ptn/security/security-center/README.md b/avm/ptn/security/security-center/README.md index ccd4a5c3eb..d537c3c74f 100644 --- a/avm/ptn/security/security-center/README.md +++ b/avm/ptn/security/security-center/README.md @@ -60,7 +60,7 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -85,6 +85,23 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/security/security-center:' + +// Required parameters +param scope = '' +param workspaceResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using default parameter set_ This instance deploys the module with default parameters. @@ -120,7 +137,7 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -159,6 +176,31 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/security/security-center:' + +// Required parameters +param scope = '' +param workspaceResourceId = '' +// Non-required parameters +param deviceSecurityGroupProperties = {} +param ioTSecuritySolutionProperties = {} +param location = '' +param securityContactProperties = { + alertNotifications: 'Off' + alertsToAdmins: 'Off' + email: 'foo@contoso.com' + phone: '+12345678' +} +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -186,7 +228,7 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -211,6 +253,23 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/security/security-center:' + +// Required parameters +param scope = '' +param workspaceResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/README.md b/avm/ptn/virtual-machine-images/azure-image-builder/README.md index 0b1e08858b..a161d38594 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/README.md +++ b/avm/ptn/virtual-machine-images/azure-image-builder/README.md @@ -35,15 +35,15 @@ This module provides you with a packaged solution to create custom images using | `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/storageAccounts/fileServices) | +| `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/storageAccounts/localUsers) | +| `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/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | -| `Microsoft.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/imageTemplates) | +| `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) | +| `Microsoft.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2023-07-01/imageTemplates) | ## Usage examples @@ -106,7 +106,7 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

-via JSON Parameter file +via JSON parameters file ```json { @@ -161,6 +161,43 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = [ + { + hyperVGeneration: 'V2' + name: 'sid-linux' + offer: 'devops_linux' + osType: 'Linux' + publisher: 'devops' + sku: 'devops_linux_az' + } +] +param computeGalleryName = 'galapvmiaibmin' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountName = 'stapvmiaibmin' +param deploymentsToPerform = '' +param location = '' +param resourceGroupName = '' +``` + +
+

+ ### Example 2: _Deploying all resources_ This instance deploys the module with the conditions set up to deploy all resource and build the image. @@ -239,7 +276,7 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

-via JSON Parameter file +via JSON parameters file ```json { @@ -331,6 +368,74 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = [ + { + hyperVGeneration: 'V2' + name: '' + offer: 'devops_linux' + osType: 'Linux' + publisher: 'devops' + sku: 'devops_linux_az' + } +] +param computeGalleryName = 'galapvmiaiba' +param imageTemplateImageSource = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'canonical' + sku: '22_04-lts-gen2' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountContainerName = '' +param assetsStorageAccountName = '' +param deploymentsToPerform = '' +param imageTemplateCustomizationSteps = [ + { + name: 'PowerShell installation' + scriptUri: '' + type: 'Shell' + } + { + destination: '' + name: '' + sourceUri: '' + type: 'File' + } + { + inline: [ + 'pwsh \'\'' + ] + name: 'Software installation' + type: 'Shell' + } +] +param location = '' +param resourceGroupName = '' +param storageAccountFilesToUpload = [ + { + name: '' + value: '' + } + { + name: '' + value: '' + } +] +``` + +
+

+ ### Example 3: _Deploying only the assets & image_ This instance deploys the module with the conditions set up to only update the assets on the assets storage account and build the image, assuming all dependencies are setup. @@ -390,7 +495,7 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

-via JSON Parameter file +via JSON parameters file ```json { @@ -477,6 +582,55 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = '' +param computeGalleryName = '' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountContainerName = '' +param assetsStorageAccountName = '' +param deploymentScriptManagedIdentityName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptSubnetName = '' +param deploymentsToPerform = 'Only assets & image' +param imageManagedIdentityName = '' +param imageSubnetName = '' +param imageTemplateCustomizationSteps = [ + { + name: 'Example script' + scriptUri: '' + type: 'Shell' + } +] +param imageTemplateResourceGroupName = '' +param location = '' +param resourceGroupName = '' +param storageAccountFilesToUpload = [ + { + name: '' + value: '' + } +] +param virtualNetworkName = '' +``` + +
+

+ ### Example 4: _Deploying only the base services_ This instance deploys the module with the conditions set up to only deploy the base resources, that is everything but the image. @@ -525,7 +679,7 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

-via JSON Parameter file +via JSON parameters file ```json { @@ -583,6 +737,44 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = [ + { + hyperVGeneration: 'V2' + name: '' + offer: 'devops_linux' + osType: 'Linux' + publisher: 'devops' + sku: 'devops_linux_az' + } +] +param computeGalleryName = 'galapvmiaibob' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountName = 'stapvmiaibob' +param deploymentsToPerform = 'Only base' +param imageManagedIdentityName = 'msi-it-apvmiaibob' +param location = '' +param resourceGroupName = '' +``` + +
+

+ ### Example 5: _Deploying only the image_ This instance deploys the module with the conditions set up to only deploy and bake the image, assuming all dependencies are setup. @@ -634,7 +826,7 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

-via JSON Parameter file +via JSON parameters file ```json { @@ -707,6 +899,47 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = '' +param computeGalleryName = '' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param deploymentScriptManagedIdentityName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptSubnetName = '' +param deploymentsToPerform = 'Only image' +param imageManagedIdentityName = '' +param imageSubnetName = '' +param imageTemplateCustomizationSteps = [ + { + name: 'Example script' + scriptUri: '' + type: 'Shell' + } +] +param imageTemplateResourceGroupName = '' +param location = '' +param resourceGroupName = '' +param virtualNetworkName = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/aad/domain-service/README.md b/avm/res/aad/domain-service/README.md index 1a8c5627a8..c7f0fbcee7 100644 --- a/avm/res/aad/domain-service/README.md +++ b/avm/res/aad/domain-service/README.md @@ -99,7 +99,7 @@ module domainService 'br/public:avm/res/aad/domain-service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -186,6 +186,65 @@ module domainService 'br/public:avm/res/aad/domain-service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/aad/domain-service:' + +// Required parameters +param domainName = 'onmicrosoft.com' +// Non-required parameters +param additionalRecipients = [ + '@noreply.github.com' +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param externalAccess = 'Enabled' +param ldaps = 'Enabled' +param location = '' +param lock = { + kind: 'None' + name: 'myCustomLockName' +} +param name = 'aaddswaf001' +param pfxCertificate = '' +param pfxCertificatePassword = '' +param replicaSets = [ + { + location: 'NorthEurope' + subnetId: '' + } +] +param sku = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/alerts-management/action-rule/README.md b/avm/res/alerts-management/action-rule/README.md index 658f855769..5bb136e59b 100644 --- a/avm/res/alerts-management/action-rule/README.md +++ b/avm/res/alerts-management/action-rule/README.md @@ -56,7 +56,7 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/alerts-management/action-rule:' + +// Required parameters +param name = 'aprmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -232,7 +248,7 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -398,6 +414,150 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/alerts-management/action-rule:' + +// Required parameters +param name = 'aprmax001' +// Non-required parameters +param actions = [ + { + actionGroupIds: [ + '' + ] + actionType: 'AddActionGroups' + } +] +param aprDescription = 'Test deployment of the module with the max set of parameters.' +param conditions = [ + { + field: 'AlertContext' + operator: 'NotEquals' + values: [ + 'myAlertContext' + ] + } + { + field: 'AlertRuleId' + operator: 'Equals' + values: [ + '' + ] + } + { + field: 'AlertRuleName' + operator: 'Equals' + values: [ + '' + ] + } + { + field: 'Description' + operator: 'Contains' + values: [ + 'myAlertRuleDescription' + ] + } + { + field: 'MonitorService' + operator: 'Equals' + values: [ + 'ActivityLog Administrative' + ] + } + { + field: 'MonitorCondition' + operator: 'Equals' + values: [ + 'Fired' + ] + } + { + field: 'TargetResourceType' + operator: 'DoesNotContain' + values: [ + 'myAlertResourceType' + ] + } + { + field: 'TargetResource' + operator: 'Equals' + values: [ + 'myAlertResource1' + 'myAlertResource2' + ] + } + { + field: 'TargetResourceGroup' + operator: 'Equals' + values: [ + '' + ] + } + { + field: 'Severity' + operator: 'Equals' + values: [ + 'Sev0' + 'Sev1' + 'Sev2' + 'Sev3' + 'Sev4' + ] + } + { + field: 'SignalType' + operator: 'Equals' + values: [ + 'Health' + 'Log' + 'Metric' + 'Unknown' + ] + } +] +param enabled = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'a66da6bc-b3ee-484e-9bdb-9294938bb327' + 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. @@ -436,7 +596,7 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -476,6 +636,34 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/alerts-management/action-rule:' + +// Required parameters +param name = 'aprwaf001' +// Non-required parameters +param actions = [ + { + actionGroupIds: [ + '' + ] + actionType: 'AddActionGroups' + } +] +param aprDescription = 'Test deployment of the module with the waf aligned set of parameters.' +param location = '' +param scopes = [ + '' +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/analysis-services/server/README.md b/avm/res/analysis-services/server/README.md index 32cb2ff12e..746d2e0701 100644 --- a/avm/res/analysis-services/server/README.md +++ b/avm/res/analysis-services/server/README.md @@ -62,7 +62,7 @@ module server 'br/public:avm/res/analysis-services/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,22 @@ module server 'br/public:avm/res/analysis-services/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/analysis-services/server:' + +// Required parameters +param name = 'assmin' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -172,7 +188,7 @@ module server 'br/public:avm/res/analysis-services/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -270,6 +286,84 @@ module server 'br/public:avm/res/analysis-services/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/analysis-services/server:' + +// Required parameters +param name = 'assmax' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'Engine' + } + { + category: 'Service' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallSettings = { + enablePowerBIService: true + firewallRules: [ + { + firewallRuleName: 'AllowFromAll' + rangeEnd: '255.255.255.255' + rangeStart: '0.0.0.0' + } + ] +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '0a657697-dd80-427e-b1bc-7970ab74f937' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 1 +param skuName = 'S0' +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. @@ -339,7 +433,7 @@ module server 'br/public:avm/res/analysis-services/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -416,6 +510,65 @@ module server 'br/public:avm/res/analysis-services/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/analysis-services/server:' + +// Required parameters +param name = 'asswaf' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'Engine' + } + { + category: 'Service' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallSettings = { + enablePowerBIService: true + firewallRules: [ + { + firewallRuleName: 'AllowFromAll' + rangeEnd: '255.255.255.255' + rangeStart: '0.0.0.0' + } + ] +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param skuCapacity = 1 +param skuName = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/api-management/service/README.md b/avm/res/api-management/service/README.md index b95709dc50..42c1636201 100644 --- a/avm/res/api-management/service/README.md +++ b/avm/res/api-management/service/README.md @@ -80,7 +80,7 @@ module service 'br/public:avm/res/api-management/service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -111,6 +111,25 @@ module service 'br/public:avm/res/api-management/service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apiscon001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +param sku = 'Consumption' +``` + +
+

+ ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -139,7 +158,7 @@ module service 'br/public:avm/res/api-management/service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -167,6 +186,24 @@ module service 'br/public:avm/res/api-management/service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apismin001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 3: _Deploying a Developer SKU_ This instance deploys the module using a Developer SKU. @@ -196,7 +233,7 @@ module service 'br/public:avm/res/api-management/service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +264,25 @@ module service 'br/public:avm/res/api-management/service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apisdev001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +param sku = 'Developer' +``` + +
+

+ ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -458,7 +514,7 @@ module service 'br/public:avm/res/api-management/service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -731,6 +787,227 @@ module service 'br/public:avm/res/api-management/service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apismax001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param additionalLocations = [ + { + disableGateway: false + location: '' + publicIpAddressId: '' + sku: { + capacity: 1 + name: 'Premium' + } + virtualNetworkConfiguration: { + subnetResourceId: '' + } + } +] +param apiDiagnostics = [ + { + apiName: 'echo-api' + loggerName: 'logger' + metrics: true + name: 'applicationinsights' + } +] +param apis = [ + { + apiVersionSet: { + name: 'echo-version-set' + properties: { + description: 'echo-version-set' + displayName: 'echo-version-set' + versioningScheme: 'Segment' + } + } + displayName: 'Echo API' + name: 'echo-api' + path: 'echo' + serviceUrl: 'http://echoapi.cloudapp.net/api' + } +] +param authorizationServers = { + secureList: [ + { + authorizationEndpoint: '' + clientId: 'apimclientid' + clientRegistrationEndpoint: 'http://localhost' + clientSecret: '' + displayName: 'AuthServer1' + grantTypes: [ + 'authorizationCode' + ] + name: 'AuthServer1' + tokenEndpoint: '' + } + ] +} +param backends = [ + { + name: 'backend' + tls: { + validateCertificateChain: false + validateCertificateName: false + } + url: 'http://echoapi.cloudapp.net/api' + } +] +param caches = [ + { + connectionString: 'connectionstringtest' + name: 'westeurope' + useFromLocation: 'westeurope' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param identityProviders = [ + { + allowedTenants: [ + 'mytenant.onmicrosoft.com' + ] + authority: '' + clientId: 'apimClientid' + clientLibrary: 'MSAL-2' + clientSecret: 'apimSlientSecret' + name: 'aad' + signinTenant: 'mytenant.onmicrosoft.com' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param loggers = [ + { + credentials: { + instrumentationKey: '' + } + description: 'Logger to Azure Application Insights' + isBuffered: false + loggerType: 'applicationInsights' + name: 'logger' + resourceId: '' + } +] +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param namedValues = [ + { + displayName: 'apimkey' + name: 'apimkey' + secret: true + } +] +param policies = [ + { + format: 'xml' + value: ' ' + } +] +param portalsettings = [ + { + name: 'signin' + properties: { + enabled: false + } + } + { + name: 'signup' + properties: { + enabled: false + termsOfService: { + consentRequired: false + enabled: false + } + } + } +] +param products = [ + { + apis: [ + { + name: 'echo-api' + } + ] + approvalRequired: false + displayName: 'Starter' + groups: [ + { + name: 'developers' + } + ] + name: 'Starter' + subscriptionRequired: false + } +] +param publicIpAddressResourceId = '' +param roleAssignments = [ + { + name: '6352c3e3-ac6b-43d5-ac43-1077ff373721' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param subnetResourceId = '' +param subscriptions = [ + { + displayName: 'testArmSubscriptionAllApis' + name: 'testArmSubscriptionAllApis' + scope: '/apis' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkType = 'Internal' +``` + +
+

+ ### Example 5: _Deploying an APIM v2 sku_ This instance deploys the module using a v2 SKU. @@ -760,7 +1037,7 @@ module service 'br/public:avm/res/api-management/service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -791,6 +1068,25 @@ module service 'br/public:avm/res/api-management/service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apisv2s001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +param sku = 'BasicV2' +``` + +
+

+ ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -999,7 +1295,7 @@ module service 'br/public:avm/res/api-management/service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1241,6 +1537,204 @@ module service 'br/public:avm/res/api-management/service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apiswaf001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param additionalLocations = [ + { + disableGateway: false + location: 'westus' + sku: { + capacity: 1 + name: 'Premium' + } + } +] +param apis = [ + { + apiVersionSet: { + name: 'echo-version-set' + properties: { + description: 'An echo API version set' + displayName: 'Echo version set' + versioningScheme: 'Segment' + } + } + description: 'An echo API service' + displayName: 'Echo API' + name: 'echo-api' + path: 'echo' + serviceUrl: 'https://echoapi.cloudapp.net/api' + } +] +param authorizationServers = { + secureList: [ + { + authorizationEndpoint: '' + clientId: 'apimClientid' + clientRegistrationEndpoint: 'https://localhost' + clientSecret: '' + displayName: 'AuthServer1' + grantTypes: [ + 'authorizationCode' + ] + name: 'AuthServer1' + tokenEndpoint: '' + } + ] +} +param backends = [ + { + name: 'backend' + tls: { + validateCertificateChain: false + validateCertificateName: false + } + url: 'https://echoapi.cloudapp.net/api' + } +] +param caches = [ + { + connectionString: 'connectionstringtest' + name: 'westeurope' + useFromLocation: 'westeurope' + } +] +param customProperties = { + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Protocols.Server.Http2': 'True' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Ssl30': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls10': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls11': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA256': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_GCM_SHA256': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA256': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TripleDes168': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Ssl30': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls10': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls11': 'False' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param identityProviders = [ + { + allowedTenants: [ + 'mytenant.onmicrosoft.com' + ] + authority: '' + clientId: 'apimClientid' + clientLibrary: 'MSAL-2' + clientSecret: '' + name: 'aad' + signinTenant: 'mytenant.onmicrosoft.com' + } +] +param location = '' +param loggers = [ + { + credentials: { + instrumentationKey: '' + } + description: 'Logger to Azure Application Insights' + isBuffered: false + loggerType: 'applicationInsights' + name: 'logger' + resourceId: '' + } +] +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param minApiVersion = '2022-08-01' +param namedValues = [ + { + displayName: 'apimkey' + name: 'apimkey' + secret: true + } +] +param policies = [ + { + format: 'xml' + value: ' ' + } +] +param portalsettings = [ + { + name: 'signin' + properties: { + enabled: false + } + } + { + name: 'signup' + properties: { + enabled: false + termsOfService: { + consentRequired: false + enabled: false + } + } + } +] +param products = [ + { + apis: [ + { + name: 'echo-api' + } + ] + approvalRequired: true + description: 'This is an echo API' + displayName: 'Echo API' + groups: [ + { + name: 'developers' + } + ] + name: 'Starter' + subscriptionRequired: true + terms: 'By accessing or using the services provided by Echo API through Azure API Management, you agree to be bound by these Terms of Use. These terms may be updated from time to time, and your continued use of the services constitutes acceptance of any changes.' + } +] +param subscriptions = [ + { + displayName: 'testArmSubscriptionAllApis' + name: 'testArmSubscriptionAllApis' + scope: '/apis' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/app-configuration/configuration-store/README.md b/avm/res/app-configuration/configuration-store/README.md index 62362ac7a1..e7a84828bf 100644 --- a/avm/res/app-configuration/configuration-store/README.md +++ b/avm/res/app-configuration/configuration-store/README.md @@ -65,7 +65,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

-via JSON Parameter file +via JSON parameters file ```json { @@ -90,6 +90,23 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accmin001' +// Non-required parameters +param enablePurgeProtection = false +param location = '' +``` + +
+

+ ### Example 2: _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. @@ -144,7 +161,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

-via JSON Parameter file +via JSON parameters file ```json { @@ -208,6 +225,50 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accencr001' +// Non-required parameters +param createMode = 'Default' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param disableLocalAuth = '' +param enablePurgeProtection = false +param keyValues = [ + { + contentType: 'contentType' + name: 'keyName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + value: 'valueName' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param softDeleteRetentionInDays = 1 +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -319,7 +380,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

-via JSON Parameter file +via JSON parameters file ```json { @@ -448,6 +509,107 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accmax001' +// Non-required parameters +param createMode = 'Default' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = '' +param enablePurgeProtection = false +param keyValues = [ + { + contentType: 'contentType' + name: 'keyName' + roleAssignments: [ + { + name: '56e2c190-b31e-4518-84de-170b8a5c1b24' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + value: 'valueName' + } + { + name: 'keyName2' + value: 'valueName2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param replicaLocations = [ + 'centralus' + 'westus' +] +param roleAssignments = [ + { + name: '695044c2-3f1f-4843-970a-bed584b95a9a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param softDeleteRetentionInDays = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 4: _Private endpoint-enabled deployment_ This instance deploys the module with private endpoints. @@ -504,7 +666,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

-via JSON Parameter file +via JSON parameters file ```json { @@ -564,6 +726,52 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accpe001' +// Non-required parameters +param createMode = 'Default' +param enablePurgeProtection = false +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param softDeleteRetentionInDays = 1 +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -618,7 +826,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

-via JSON Parameter file +via JSON parameters file ```json { @@ -684,6 +892,50 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accwaf001' +// Non-required parameters +param createMode = 'Default' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = '' +param enablePurgeProtection = false +param keyValues = [ + { + contentType: 'contentType' + name: 'keyName' + value: 'valueName' + } +] +param location = '' +param replicaLocations = [ + 'centralus' + 'westus' +] +param softDeleteRetentionInDays = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/app/container-app/README.md b/avm/res/app/container-app/README.md index a032f3411f..b6c1bce086 100644 --- a/avm/res/app/container-app/README.md +++ b/avm/res/app/container-app/README.md @@ -69,7 +69,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -106,6 +106,33 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acamin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Without ingress enabled_ This instance deploys the module with ingress traffic completely disabled. @@ -144,7 +171,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -184,6 +211,34 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acapriv001' +// Non-required parameters +param disableIngress = true +param location = '' +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -293,7 +348,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -412,6 +467,105 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + env: [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } + ] + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acamax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'e9bac1ee-aebe-4513-9337-49e87a7be05e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param secrets = { + secureList: [ + { + name: 'containerappstoredsecret' + value: '' + } + { + identity: '' + keyVaultUrl: '' + name: 'keyvaultstoredsecret' + } + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
+

+ ### Example 4: _VNet integrated container app deployment_ This instance deploys the container app in a managed environment with a virtual network using TCP ingress. @@ -460,7 +614,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -518,6 +672,44 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acavnet001' +// Non-required parameters +param additionalPortMappings = [ + { + exposedPort: 8080 + external: false + targetPort: 8080 + } +] +param ingressAllowInsecure = false +param ingressExternal = false +param ingressTargetPort = 80 +param ingressTransport = 'tcp' +param location = '' +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -587,7 +779,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -666,6 +858,65 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acawaf001' +// Non-required parameters +param ingressAllowInsecure = false +param ingressExternal = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/app/job/README.md b/avm/res/app/job/README.md index 792068064b..51e3119966 100644 --- a/avm/res/app/job/README.md +++ b/avm/res/app/job/README.md @@ -66,7 +66,7 @@ module job 'br/public:avm/res/app/job:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -105,6 +105,31 @@ module job 'br/public:avm/res/app/job:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + } +] +param environmentResourceId = '' +param name = 'ajcon001' +param triggerType = 'Manual' +// Non-required parameters +param location = '' +param manualTriggerConfig = {} +``` + +
+

+ ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -144,7 +169,7 @@ module job 'br/public:avm/res/app/job:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -187,6 +212,35 @@ module job 'br/public:avm/res/app/job:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '0.25' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'ajmin001' +param triggerType = 'Manual' +// Non-required parameters +param location = '' +param manualTriggerConfig = {} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -349,7 +403,7 @@ module job 'br/public:avm/res/app/job:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -529,6 +583,158 @@ module job 'br/public:avm/res/app/job:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + env: [ + { + name: 'AZURE_STORAGE_QUEUE_NAME' + value: '' + } + { + name: 'AZURE_STORAGE_CONNECTION_STRING' + secretRef: 'connection-string' + } + ] + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '1.25' + memory: '1.5Gi' + } + volumeMounts: [ + { + mountPath: '/mnt/data' + volumeName: 'ajmaxemptydir' + } + ] + } + { + args: [ + 'arg1' + 'arg2' + ] + command: [ + '-c' + '/bin/bash' + 'echo hello' + 'sleep 100000' + ] + env: [ + { + name: 'SOME_ENV_VAR' + value: 'some-value' + } + ] + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'second-simple-container' + } +] +param environmentResourceId = '' +param name = 'ajmax001' +param triggerType = 'Event' +// Non-required parameters +param eventTriggerConfig = { + parallelism: 1 + replicaCompletionCount: 1 + scale: { + maxExecutions: 1 + minExecutions: 1 + pollingInterval: 55 + rules: [ + { + auth: [ + { + secretRef: 'connectionString' + triggerParameter: 'connection' + } + ] + metadata: { + queueName: '' + storageAccountResourceId: '' + } + name: 'queue' + type: 'azure-queue' + } + ] + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'be1bb251-6a44-49f7-8658-d836d0049fc4' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param secrets = [ + { + name: 'connection-string' + value: '' + } +] +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param volumes = [ + { + name: 'ajmaxemptydir' + storageType: 'EmptyDir' + } +] +param workloadProfileName = '' +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -592,7 +798,7 @@ module job 'br/public:avm/res/app/job:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -663,6 +869,59 @@ module job 'br/public:avm/res/app/job:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '0.25' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'ajwaf001' +param triggerType = 'Schedule' +// Non-required parameters +param location = '' +param scheduleTriggerConfig = { + cronExpression: '0 0 * * *' +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param workloadProfileName = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/app/managed-environment/README.md b/avm/res/app/managed-environment/README.md index 75b860ddd7..3d5b5191c4 100644 --- a/avm/res/app/managed-environment/README.md +++ b/avm/res/app/managed-environment/README.md @@ -72,7 +72,7 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -125,6 +125,37 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/managed-environment:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'amemin001' +// Non-required parameters +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetId = '' +param internal = true +param location = '' +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -227,7 +258,7 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -357,6 +388,98 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/managed-environment:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'amemax001' +// Non-required parameters +param appInsightsConnectionString = '' +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetId = '' +param internal = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param openTelemetryConfiguration = { + logsConfiguration: { + destinations: [ + 'appInsights' + ] + } + tracesConfiguration: { + destinations: [ + 'appInsights' + ] + } +} +param peerTrafficEncryption = true +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param roleAssignments = [ + { + name: '43fc5250-f111-472b-8722-f1cb4a0e754b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storages = [ + { + accessMode: 'ReadWrite' + kind: 'SMB' + shareName: 'smbfileshare' + storageAccountName: '' + } + { + accessMode: 'ReadWrite' + kind: 'NFS' + shareName: 'nfsfileshare' + storageAccountName: '' + } +] +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -423,7 +546,7 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -507,6 +630,62 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/managed-environment:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'amewaf001' +// Non-required parameters +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetId = '' +param internal = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/automation/automation-account/README.md b/avm/res/automation/automation-account/README.md index d6b50e257b..549a0c129e 100644 --- a/avm/res/automation/automation-account/README.md +++ b/avm/res/automation/automation-account/README.md @@ -70,7 +70,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,22 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

+

+ +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. @@ -128,7 +144,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

via JSON Parameter file +via JSON parameters file ```json { @@ -164,6 +180,32 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

+

+ +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. @@ -422,7 +464,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

via JSON Parameter file +via JSON parameters file ```json { @@ -708,6 +750,254 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

+

+ +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: 'Updates' + product: 'OMSGallery' + 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. @@ -917,7 +1207,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1150,6 +1440,205 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

+

+ +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: 'Updates' + product: 'OMSGallery' + 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: '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** diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index 788df94957..0cf0a66b37 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -62,7 +62,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,23 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

+

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

+ ### Example 2: _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. @@ -128,7 +145,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -177,6 +194,37 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/batch/batch-account:' + +// Required parameters +param name = 'bbaencr001' +param storageAccountId = '' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param poolAllocationMode = 'BatchService' +param storageAuthenticationMode = 'BatchAccountManagedIdentity' +param tags = { + 'hidden-title': 'This is visible in the resource name' +} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -346,7 +394,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -533,6 +581,165 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/batch/batch-account:' + +// Required parameters +param name = 'bbamax001' +param storageAccountId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param networkProfile = { + accountAccess: { + allowedIpRules: [ + '40.74.28.0/23' + ] + defaultAction: 'Deny' + } + nodeManagementAccess: { + allowedIpRules: [ + '40.74.28.0/23' + ] + } +} +param poolAllocationMode = 'BatchService' +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.batch.com' + ipAddresses: [ + '10.0.16.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'batchAccount' + memberName: 'batchAccount' + privateIPAddress: '10.0.16.10' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + name: '9afa4fb3-2157-40db-aebb-039ce73c50ca' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + service: 'batchAccount' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'batchAccount' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'nodeManagement' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param roleAssignments = [ + { + name: 'd57821b0-52b3-4a42-9799-533a9cdb7eec' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageAccessIdentityResourceId = '' +param storageAuthenticationMode = 'BatchAccountManagedIdentity' +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. @@ -596,7 +803,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -673,6 +880,59 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/batch/batch-account:' + +// Required parameters +param name = 'bbawaf001' +param storageAccountId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param poolAllocationMode = 'BatchService' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'batchAccount' + subnetResourceId: '' + } +] +param storageAccessIdentityResourceId = '' +param storageAuthenticationMode = 'BatchAccountManagedIdentity' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/cache/redis/README.md b/avm/res/cache/redis/README.md index addd537447..de250d1472 100644 --- a/avm/res/cache/redis/README.md +++ b/avm/res/cache/redis/README.md @@ -64,7 +64,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module redis 'br/public:avm/res/cache/redis:' = {

+

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

+ ### Example 2: _Using EntraID authentication_ This instance deploys the module with EntraID authentication. @@ -115,7 +131,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -142,6 +158,25 @@ module redis 'br/public:avm/res/cache/redis:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crentrid001' +// Non-required parameters +param location = '' +param redisConfiguration = { + 'aad-enabled': 'true' +} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -271,7 +306,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -424,6 +459,125 @@ module redis 'br/public:avm/res/cache/redis:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crmax001' +// Non-required parameters +param capacity = 2 +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableNonSslPort = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param minimumTlsVersion = '1.2' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + name: '8d6043f5-8a22-447f-bc31-23d23e09de6c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param redisVersion = '6' +param roleAssignments = [ + { + name: 'f20e5c94-a697-421e-8768-d576399dbd87' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param shardCount = 1 +param skuName = 'Premium' +param tags = { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Redis Cache' +} +param zoneRedundant = true +param zones = [ + 1 + 2 +] +``` + +
+

+ ### Example 4: _Passive Geo-Replicated Redis Cache_ This instance deploys the module with geo-replication enabled. @@ -468,7 +622,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -530,6 +684,40 @@ module redis 'br/public:avm/res/cache/redis:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crpgeo001' +// Non-required parameters +param capacity = 2 +param enableNonSslPort = true +param geoReplicationObject = { + linkedRedisCacheLocation: '' + linkedRedisCacheResourceId: '' + name: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param minimumTlsVersion = '1.2' +param redisVersion = '6' +param replicasPerMaster = 1 +param replicasPerPrimary = 1 +param shardCount = 1 +param skuName = 'Premium' +param zoneRedundant = false +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -612,7 +800,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -720,6 +908,78 @@ module redis 'br/public:avm/res/cache/redis:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crwaf001' +// Non-required parameters +param capacity = 2 +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableNonSslPort = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param minimumTlsVersion = '1.2' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param redisVersion = '6' +param replicasPerMaster = 3 +param replicasPerPrimary = 3 +param shardCount = 1 +param skuName = 'Premium' +param tags = { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Redis Cache' +} +param zoneRedundant = true +param zones = [ + 1 + 2 + 3 +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index e2de8fbea8..0bd698095d 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -154,7 +154,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -275,6 +275,107 @@ module profile 'br/public:avm/res/cdn/profile:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpafdp' +param sku = 'Premium_AzureFrontDoor' +// Non-required parameters +param afdEndpoints = [ + { + name: 'dep-test-cdnpafdp-afd-endpoint' + routes: [ + { + customDomainNames: [ + 'dep-test-cdnpafdp-custom-domain' + ] + name: 'dep-test-cdnpafdp-afd-route' + originGroupName: 'dep-test-cdnpafdp-origin-group' + ruleSets: [ + { + name: 'deptestcdnpafdpruleset' + } + ] + } + ] + } +] +param customDomains = [ + { + certificateType: 'ManagedCertificate' + hostName: 'dep-test-cdnpafdp-custom-domain.azurewebsites.net' + name: 'dep-test-cdnpafdp-custom-domain' + } +] +param location = 'global' +param originGroups = [ + { + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + name: 'dep-test-cdnpafdp-origin-group' + origins: [ + { + hostName: 'dep-test-cdnpafdp-origin.azurewebsites.net' + name: 'dep-test-cdnpafdp-origin' + } + ] + } +] +param originResponseTimeoutSeconds = 60 +param ruleSets = [ + { + name: 'deptestcdnpafdpruleset' + rules: [ + { + actions: [ + { + name: 'UrlRedirect' + parameters: { + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + customPath: '/test123' + destinationProtocol: 'Https' + redirectType: 'PermanentRedirect' + typeName: 'DeliveryRuleUrlRedirectActionParameters' + } + } + ] + name: 'deptestcdnpafdprule' + order: 1 + } + ] + } +] +param securityPolicies = [ + { + associations: [ + { + domains: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + } + ] + name: 'deptestcdnpafdpsecpol' + wafPolicyResourceId: '' + } +] +``` + +
+

+ ### Example 2: _As Azure Front Door_ This instance deploys the module as Azure Front Door. @@ -368,7 +469,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -469,6 +570,89 @@ module profile 'br/public:avm/res/cdn/profile:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpafd' +param sku = 'Standard_AzureFrontDoor' +// Non-required parameters +param afdEndpoints = [ + { + name: 'dep-test-cdnpafd-afd-endpoint' + routes: [ + { + customDomainNames: [ + 'dep-test-cdnpafd-custom-domain' + ] + name: 'dep-test-cdnpafd-afd-route' + originGroupName: 'dep-test-cdnpafd-origin-group' + ruleSets: [ + { + name: 'deptestcdnpafdruleset' + } + ] + } + ] + } +] +param customDomains = [ + { + certificateType: 'ManagedCertificate' + hostName: 'dep-test-cdnpafd-custom-domain.azurewebsites.net' + name: 'dep-test-cdnpafd-custom-domain' + } +] +param location = 'global' +param originGroups = [ + { + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + name: 'dep-test-cdnpafd-origin-group' + origins: [ + { + hostName: 'dep-test-cdnpafd-origin.azurewebsites.net' + name: 'dep-test-cdnpafd-origin' + } + ] + } +] +param originResponseTimeoutSeconds = 60 +param ruleSets = [ + { + name: 'deptestcdnpafdruleset' + rules: [ + { + actions: [ + { + name: 'UrlRedirect' + parameters: { + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + customPath: '/test123' + destinationProtocol: 'Https' + redirectType: 'PermanentRedirect' + typeName: 'DeliveryRuleUrlRedirectActionParameters' + } + } + ] + name: 'deptestcdnpafdrule' + order: 1 + } + ] + } +] +``` + +
+

+ ### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -496,7 +680,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -521,6 +705,23 @@ module profile 'br/public:avm/res/cdn/profile:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpmin' +param sku = 'Standard_Microsoft' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -602,7 +803,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -689,6 +890,77 @@ module profile 'br/public:avm/res/cdn/profile:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpmax' +param sku = 'Standard_Verizon' +// Non-required parameters +param endpointProperties = { + contentTypesToCompress: [ + 'application/javascript' + 'application/json' + 'application/x-javascript' + 'application/xml' + 'text/css' + 'text/html' + 'text/javascript' + 'text/plain' + ] + geoFilters: [] + isCompressionEnabled: true + isHttpAllowed: true + isHttpsAllowed: true + originGroups: [] + originHostHeader: '' + origins: [ + { + name: 'dep-cdn-endpoint01' + properties: { + enabled: true + hostName: '' + httpPort: 80 + httpsPort: 443 + } + } + ] + queryStringCachingBehavior: 'IgnoreQueryString' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param originResponseTimeoutSeconds = 60 +param roleAssignments = [ + { + name: '50362c78-6910-43c3-8639-9cae123943bb' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -747,7 +1019,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -807,6 +1079,54 @@ module profile 'br/public:avm/res/cdn/profile:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpwaf' +param sku = 'Standard_Verizon' +// Non-required parameters +param endpointProperties = { + contentTypesToCompress: [ + 'application/javascript' + 'application/json' + 'application/x-javascript' + 'application/xml' + 'text/css' + 'text/html' + 'text/javascript' + 'text/plain' + ] + geoFilters: [] + isCompressionEnabled: true + isHttpAllowed: true + isHttpsAllowed: true + originGroups: [] + originHostHeader: '' + origins: [ + { + name: 'dep-cdn-endpoint01' + properties: { + enabled: true + hostName: '' + httpPort: 80 + httpsPort: 443 + } + } + ] + queryStringCachingBehavior: 'IgnoreQueryString' +} +param location = '' +param originResponseTimeoutSeconds = 60 +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 7509f836a8..fb852b55a3 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -95,7 +95,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -153,6 +153,48 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'AIServices' +param name = 'csadp003' +// Non-required parameters +param customSubDomainName = 'xcsadpai' +param deployments = [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0301' + } + name: 'gpt-35-turbo' + sku: { + capacity: 10 + name: 'Standard' + } + } +] +param location = '' +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + '' + ] + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +``` + +
+

+ ### Example 2: _Using `AIServices` with `deployments` in parameter set_ This instance deploys the module with the AI model deployment feature. @@ -195,7 +237,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -239,6 +281,38 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'AIServices' +param name = 'csad002' +// Non-required parameters +param customSubDomainName = 'xcsadai' +param deployments = [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0301' + } + name: 'gpt-35-turbo' + sku: { + capacity: 10 + name: 'Standard' + } + } +] +param location = '' +``` + +
+

+ ### Example 3: _Storing keys of service in key vault_ This instance deploys the module and stores its keys in a key vault. @@ -271,7 +345,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -303,6 +377,28 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csakv001' +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + accessKey1Name: 'csakv001-accessKey1' + accessKey2Name: 'csakv001-accessKey2' + keyVaultResourceId: '' +} +``` + +
+

+ ### Example 4: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -330,7 +426,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -355,6 +451,23 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csamin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 5: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -492,7 +605,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -647,6 +760,133 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'Face' +param name = 'csamax001' +// Non-required parameters +param customSubDomainName = 'xcsamax' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'RequestResponse' + } + { + category: 'Audit' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param networkAcls = { + defaultAction: 'Deny' + ipRules: [ + { + value: '40.74.28.0/23' + } + ] + virtualNetworkRules: [ + { + id: '' + ignoreMissingVnetServiceEndpoint: false + } + ] +} +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.account.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'account' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: 'db64fe2f-3995-4ae0-86ef-97511d5b84e3' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 6: _Using `OpenAI` and `deployments` in parameter set with private endpoint_ This instance deploys the module with the AI model deployment feature and private endpoint. @@ -698,7 +938,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -755,6 +995,47 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'OpenAI' +param name = 'csoai002' +// Non-required parameters +param customSubDomainName = 'xcsoaiai' +param deployments = [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0301' + } + name: 'gpt-35-turbo' + sku: { + capacity: 10 + name: 'Standard' + } + } +] +param location = '' +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +``` + +
+

+ ### Example 7: _As Speech Service_ This instance deploys the module as a Speech Service. @@ -808,7 +1089,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -869,6 +1150,49 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csaspeech001' +// Non-required parameters +param customSubDomainName = 'speechdomain' +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sku = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### 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. @@ -906,7 +1230,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -951,6 +1275,33 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = '' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +param publicNetworkAccess = 'Enabled' +param restrictOutboundNetworkAccess = false +param sku = 'S0' +``` + +
+

+ ### 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. @@ -991,7 +1342,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1039,6 +1390,36 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csaencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param publicNetworkAccess = 'Enabled' +param restrictOutboundNetworkAccess = false +param sku = 'S0' +``` + +
+

+ ### Example 10: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1101,7 +1482,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1175,6 +1556,58 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'Face' +param name = 'csawaf001' +// Non-required parameters +param customSubDomainName = 'xcsawaf' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sku = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/communication/communication-service/README.md b/avm/res/communication/communication-service/README.md index e1d2bdd046..0ccc24ff39 100644 --- a/avm/res/communication/communication-service/README.md +++ b/avm/res/communication/communication-service/README.md @@ -58,7 +58,7 @@ module communicationService 'br/public:avm/res/communication/communication-servi

-via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,23 @@ module communicationService 'br/public:avm/res/communication/communication-servi

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/communication-service:' + +// Required parameters +param dataLocation = 'Germany' +param name = 'ccsmin001' +// Non-required parameters +param location = 'global' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -161,7 +178,7 @@ module communicationService 'br/public:avm/res/communication/communication-servi

-via JSON Parameter file +via JSON parameters file ```json { @@ -249,6 +266,74 @@ module communicationService 'br/public:avm/res/communication/communication-servi

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/communication-service:' + +// Required parameters +param dataLocation = 'Germany' +param name = 'ccsmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param linkedDomains = [ + '' +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '9237b909-e8fb-4bb8-8194-34aae537cee2' + 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. @@ -289,7 +374,7 @@ module communicationService 'br/public:avm/res/communication/communication-servi

-via JSON Parameter file +via JSON parameters file ```json { @@ -331,6 +416,36 @@ module communicationService 'br/public:avm/res/communication/communication-servi

+

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

+ ## Parameters **Required parameters** diff --git a/avm/res/communication/email-service/README.md b/avm/res/communication/email-service/README.md index 0087caf5ff..b35ca7f2e6 100644 --- a/avm/res/communication/email-service/README.md +++ b/avm/res/communication/email-service/README.md @@ -59,7 +59,7 @@ module emailService 'br/public:avm/res/communication/email-service:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module emailService 'br/public:avm/res/communication/email-service:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/email-service:' + +// Required parameters +param dataLocation = 'Europe' +param name = 'cesmin001' +// Non-required parameters +param location = 'global' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -183,7 +200,7 @@ module emailService 'br/public:avm/res/communication/email-service:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -288,6 +305,95 @@ module emailService 'br/public:avm/res/communication/email-service:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/email-service:' + +// Required parameters +param dataLocation = 'United States' +param name = 'cesmax001' +// Non-required parameters +param domains = [ + { + domainManagement: 'AzureManaged' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + name: 'AzureManagedDomain' + roleAssignments: [ + { + name: '1a441bec-9c57-49d1-9a83-b7fd62901413' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + senderUsernames: [ + { + displayName: 'Do Not Reply' + name: 'donotreply' + userName: 'DoNotReply' + } + { + displayName: 'Customer Service' + name: 'customerservice' + userName: 'CustomerService' + } + ] + tags: { + Role: 'DeploymentValidation' + } + userEngagementTracking: 'Enabled' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'bdfa5270-8a55-466d-90d0-b5e96a90fadc' + 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. @@ -320,7 +426,7 @@ module emailService 'br/public:avm/res/communication/email-service:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -352,6 +458,28 @@ module emailService 'br/public:avm/res/communication/email-service:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/email-service:' + +// Required parameters +param dataLocation = 'Germany' +param name = 'ceswaf001' +// 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** diff --git a/avm/res/compute/availability-set/README.md b/avm/res/compute/availability-set/README.md index b058766413..e6ce73d26d 100644 --- a/avm/res/compute/availability-set/README.md +++ b/avm/res/compute/availability-set/README.md @@ -56,7 +56,7 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

+

+ +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. @@ -133,7 +149,7 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -192,6 +208,51 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

+

+ +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. @@ -228,7 +289,7 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -266,6 +327,32 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

+

+ +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** diff --git a/avm/res/compute/disk-encryption-set/README.md b/avm/res/compute/disk-encryption-set/README.md index 85900913fe..aac4301261 100644 --- a/avm/res/compute/disk-encryption-set/README.md +++ b/avm/res/compute/disk-encryption-set/README.md @@ -88,7 +88,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

via JSON Parameter file +via JSON parameters file ```json { @@ -150,6 +150,52 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

+

+ +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. @@ -178,7 +224,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

via JSON Parameter file +via JSON parameters file ```json { @@ -206,6 +252,24 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

+

+ +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. @@ -267,7 +331,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

via JSON Parameter file +via JSON parameters file ```json { @@ -336,6 +400,57 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

+

+ +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. @@ -374,7 +489,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

via JSON Parameter file +via JSON parameters file ```json { @@ -416,6 +531,34 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

+

+ +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** diff --git a/avm/res/compute/disk/README.md b/avm/res/compute/disk/README.md index 3a95ddb2ad..cdacf8fc53 100644 --- a/avm/res/compute/disk/README.md +++ b/avm/res/compute/disk/README.md @@ -61,7 +61,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,25 @@ module disk 'br/public:avm/res/compute/disk:' = {

+

+ +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. @@ -122,7 +141,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -156,6 +175,26 @@ module disk 'br/public:avm/res/compute/disk:' = {

+

+ +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. @@ -187,7 +226,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +263,27 @@ module disk 'br/public:avm/res/compute/disk:' = {

+

+ +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. @@ -286,7 +346,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -366,6 +426,58 @@ module disk 'br/public:avm/res/compute/disk:' = {

+

+ +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. @@ -409,7 +521,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -468,6 +580,39 @@ module disk 'br/public:avm/res/compute/disk:' = {

+

+ +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** diff --git a/avm/res/compute/gallery/README.md b/avm/res/compute/gallery/README.md index 62c4b8041f..d0b76a9c34 100644 --- a/avm/res/compute/gallery/README.md +++ b/avm/res/compute/gallery/README.md @@ -58,7 +58,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

+

+ +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. @@ -311,7 +327,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -548,6 +564,227 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

+

+ +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 images = [ + { + 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' + } + { + 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: 'TrustedLaunch' + vCPUs: { + max: 8 + min: 2 + } + } + { + 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 + } + } + { + 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. @@ -597,7 +834,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -648,6 +885,45 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

+

+ +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** diff --git a/avm/res/compute/image/README.md b/avm/res/compute/image/README.md index 58545668c5..b4fd5878bc 100644 --- a/avm/res/compute/image/README.md +++ b/avm/res/compute/image/README.md @@ -59,7 +59,7 @@ module image 'br/public:avm/res/compute/image:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,26 @@ module image 'br/public:avm/res/compute/image:' = {

+

+ +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' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -152,7 +172,7 @@ module image 'br/public:avm/res/compute/image:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -229,6 +249,55 @@ module image 'br/public:avm/res/compute/image:' = {

+

+ +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. @@ -269,7 +338,7 @@ module image 'br/public:avm/res/compute/image:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -325,6 +394,36 @@ module image 'br/public:avm/res/compute/image:' = {

+

+ +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 location = '' +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** diff --git a/avm/res/compute/proximity-placement-group/README.md b/avm/res/compute/proximity-placement-group/README.md index 7bb3c4a857..5da6adc55e 100644 --- a/avm/res/compute/proximity-placement-group/README.md +++ b/avm/res/compute/proximity-placement-group/README.md @@ -56,7 +56,7 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

+

+ +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. @@ -148,7 +164,7 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

-via JSON Parameter file +via JSON parameters file ```json { @@ -228,6 +244,66 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

+

+ +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. @@ -275,7 +351,7 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

-via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +404,43 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

+

+ +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** diff --git a/avm/res/compute/ssh-public-key/README.md b/avm/res/compute/ssh-public-key/README.md index a4ebea4185..8b54ba0786 100644 --- a/avm/res/compute/ssh-public-key/README.md +++ b/avm/res/compute/ssh-public-key/README.md @@ -58,7 +58,7 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

+

+ +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. @@ -136,7 +152,7 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -198,6 +214,52 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

+

+ +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. @@ -252,7 +314,7 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -312,6 +374,50 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

+

+ +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** diff --git a/avm/res/compute/virtual-machine-scale-set/README.md b/avm/res/compute/virtual-machine-scale-set/README.md index febb8bfea7..123eb0d315 100644 --- a/avm/res/compute/virtual-machine-scale-set/README.md +++ b/avm/res/compute/virtual-machine-scale-set/README.md @@ -102,7 +102,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

-via JSON Parameter file +via JSON parameters file ```json { @@ -181,6 +181,63 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +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. @@ -358,7 +415,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

-via JSON Parameter file +via JSON parameters file ```json { @@ -585,6 +642,173 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +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 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 = { + 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. @@ -671,7 +895,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

-via JSON Parameter file +via JSON parameters file ```json { @@ -773,6 +997,82 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +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 = { + 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. @@ -834,7 +1134,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

-via JSON Parameter file +via JSON parameters file ```json { @@ -905,6 +1205,57 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +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 adminPassword = '' +param location = '' +``` + +
+

+ ### Example 5: _Using large parameter set for Windows_ This instance deploys the module with most of its features enabled. @@ -1082,7 +1433,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

-via JSON Parameter file +via JSON parameters file ```json { @@ -1305,6 +1656,173 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +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 adminPassword = '' +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 = { + 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. @@ -1451,7 +1969,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

-via JSON Parameter file +via JSON parameters file ```json { @@ -1637,6 +2155,142 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +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 adminPassword = '' +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 = { + 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** diff --git a/avm/res/compute/virtual-machine/README.md b/avm/res/compute/virtual-machine/README.md index 855f72b4a8..42808cbe63 100644 --- a/avm/res/compute/virtual-machine/README.md +++ b/avm/res/compute/virtual-machine/README.md @@ -119,7 +119,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -204,6 +204,65 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +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. @@ -268,7 +327,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -346,6 +405,60 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +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. @@ -639,7 +752,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -988,6 +1101,289 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +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. @@ -1273,7 +1669,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1618,6 +2014,281 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +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. @@ -1673,7 +2344,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1740,6 +2411,51 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +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. @@ -1824,7 +2540,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1926,6 +2642,80 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_DS2_v2' +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. @@ -2004,7 +2794,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -2100,6 +2890,74 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +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. @@ -2423,7 +3281,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -2806,6 +3664,319 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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: { + publicIpNameSuffix: '-pip-01' + 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: '' + } + ] + zones: [ + 1 + 2 + 3 + ] + } + 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_DS2_v2' +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. @@ -2864,7 +4035,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -2936,6 +4107,54 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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: _Using disk encryption set for the VM._ This instance deploys the module with disk enryption set. @@ -3004,7 +4223,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -3086,6 +4305,64 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param dataDisks = [ + { + diskSizeGB: 128 + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } +] +param location = '' +``` + +
+

+ ### Example 11: _Adding the VM to a VMSS._ This instance deploys the module with the minimum set of required parameters and adds it to a VMSS. @@ -3142,7 +4419,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -3212,6 +4489,52 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

+

+ +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_DS2_v2' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param location = '' +param virtualMachineScaleSetResourceId = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/consumption/budget/README.md b/avm/res/consumption/budget/README.md index 53638a6f17..a72051517a 100644 --- a/avm/res/consumption/budget/README.md +++ b/avm/res/consumption/budget/README.md @@ -59,7 +59,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,26 @@ module budget 'br/public:avm/res/consumption/budget:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbmin001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +``` + +
+

+ ### Example 2: _Using `thresholdType` `Forecasted`_ This instance deploys the module with the minimum set of required parameters and `thresholdType` `Forecasted`. @@ -120,7 +140,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -153,6 +173,27 @@ module budget 'br/public:avm/res/consumption/budget:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbfcst001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +param thresholdType = 'Forecasted' +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -194,7 +235,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -239,6 +280,37 @@ module budget 'br/public:avm/res/consumption/budget:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbmax001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +param resourceGroupFilter = [ + 'rg-group1' + 'rg-group2' +] +param thresholds = [ + 50 + 75 + 90 + 100 + 110 +] +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -276,7 +348,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -315,6 +387,33 @@ module budget 'br/public:avm/res/consumption/budget:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbwaf001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +param thresholds = [ + 50 + 75 + 90 + 100 + 110 +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/container-instance/container-group/README.md b/avm/res/container-instance/container-group/README.md index e34bffb713..e73e13b51e 100644 --- a/avm/res/container-instance/container-group/README.md +++ b/avm/res/container-instance/container-group/README.md @@ -83,7 +83,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -135,6 +135,48 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using CMK _ This instance deploys the module with a customer-managed key (CMK). @@ -232,7 +274,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -335,6 +377,93 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -441,7 +570,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -553,6 +682,102 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [ + { + name: 'CLIENT_ID' + value: 'TestClientId' + } + { + name: 'CLIENT_SECRET' + secureValue: 'TestSecret' + } + ] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 4: _Using private network_ This instance deploys the module within a virtual network. @@ -645,7 +870,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -743,6 +968,88 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 4 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + { + port: 8080 + protocol: 'Tcp' + } +] +param name = 'cicgprivate001' +// Non-required parameters +param ipAddressType = 'Private' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param subnetId = '' +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -834,7 +1141,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -929,6 +1236,87 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgwaf001' +// 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** diff --git a/avm/res/container-registry/registry/README.md b/avm/res/container-registry/registry/README.md index 02594a96ff..eb764f51d8 100644 --- a/avm/res/container-registry/registry/README.md +++ b/avm/res/container-registry/registry/README.md @@ -94,7 +94,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -150,6 +150,48 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = '' +// Non-required parameters +param acrAdminUserEnabled = false +param acrSku = 'Standard' +param cacheRules = [ + { + credentialSetResourceId: '' + name: 'customRule' + sourceRepository: 'docker.io/library/hello-world' + targetRepository: 'cached-docker-hub/hello-world' + } +] +param credentialSets = [ + { + authCredentials: [ + { + name: 'Credential1' + passwordSecretIdentifier: '' + usernameSecretIdentifier: '' + } + ] + loginServer: 'docker.io' + managedIdentities: { + systemAssigned: true + } + name: 'default' + } +] +param location = '' +``` + +
+

+ ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -177,7 +219,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -202,6 +244,23 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrmin001' +// Non-required parameters +param acrSku = 'Standard' +param location = '' +``` + +
+

+ ### Example 3: _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. @@ -240,7 +299,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -282,6 +341,34 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrencr001' +// Non-required parameters +param acrSku = 'Premium' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param publicNetworkAccess = 'Disabled' +``` + +
+

+ ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -409,7 +496,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -566,6 +653,123 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrmax001' +// Non-required parameters +param acrAdminUserEnabled = false +param acrSku = 'Premium' +param azureADAuthenticationAsArmPolicyStatus = 'enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param exportPolicyStatus = 'enabled' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param networkRuleSetIpRules = [ + { + action: 'Allow' + value: '40.74.28.0/23' + } +] +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param quarantinePolicyStatus = 'enabled' +param replications = [ + { + location: '' + name: '' + } +] +param roleAssignments = [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param softDeletePolicyDays = 7 +param softDeletePolicyStatus = 'disabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param trustPolicyStatus = 'enabled' +param webhooks = [ + { + name: 'acrx001webhook' + serviceUri: 'https://www.contoso.com/webhook' + } +] +``` + +
+

+ ### Example 5: _Using `scopeMaps` in parameter set_ This instance deploys the module with the scopeMaps feature. @@ -602,7 +806,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -638,6 +842,32 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrs001' +// Non-required parameters +param acrSku = 'Standard' +param location = '' +param scopeMaps = [ + { + actions: [ + 'repositories/*/content/read' + ] + description: 'This is a test for scopeMaps feature.' + name: 'testscopemap' + } +] +``` + +
+

+ ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -703,7 +933,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -788,6 +1018,61 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrwaf001' +// Non-required parameters +param acrAdminUserEnabled = false +param acrSku = 'Premium' +param azureADAuthenticationAsArmPolicyStatus = 'enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param exportPolicyStatus = 'enabled' +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param quarantinePolicyStatus = 'enabled' +param replications = [ + { + location: '' + name: '' + } +] +param softDeletePolicyDays = 7 +param softDeletePolicyStatus = 'disabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param trustPolicyStatus = 'enabled' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md index 2e988e1ca5..3b68c8346d 100644 --- a/avm/res/container-service/managed-cluster/README.md +++ b/avm/res/container-service/managed-cluster/README.md @@ -93,7 +93,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

via JSON Parameter file +via JSON parameters file ```json { @@ -149,6 +149,50 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csauto001' +param primaryAgentPoolProfile = [ + { + count: 3 + mode: 'System' + name: 'systempool' + vmSize: 'Standard_DS2_v2' + } +] +// Non-required parameters +param location = '' +param maintenanceConfiguration = { + maintenanceWindow: { + durationHours: 4 + schedule: { + absoluteMonthly: '' + daily: '' + relativeMonthly: '' + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-03' + startTime: '00:00' + utcOffset: '+00:00' + } +} +param managedIdentities = { + systemAssigned: true +} +``` + +
+

+ ### Example 2: _Using Azure CNI Network Plugin._ This instance deploys the module with Azure CNI network plugin . @@ -375,7 +419,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

via JSON Parameter file +via JSON parameters file ```json { @@ -653,6 +697,222 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmaz001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 1 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + proximityPlacementGroupResourceId: '' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +param autoUpgradeProfileUpgradeChannel = 'stable' +param customerManagedKey = { + keyName: '' + keyVaultNetworkAccess: 'Public' + keyVaultResourceId: '' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param diskEncryptionSetResourceId = '' +param enableAzureDefender = true +param enableAzureMonitorProfileMetrics = true +param enableKeyvaultSecretsProvider = true +param enableOidcIssuerProfile = true +param enablePodSecurityPolicy = false +param enableStorageProfileBlobCSIDriver = true +param enableStorageProfileDiskCSIDriver = true +param enableStorageProfileFileCSIDriver = true +param enableStorageProfileSnapshotController = true +param enableWorkloadIdentity = true +param fluxExtension = { + configurations: [ + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' + } + namespace: 'flux-system' + scope: 'cluster' + } + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/Azure/gitops-flux2-kustomize-helm-mt' + } + kustomizations: { + apps: { + dependsOn: [ + 'infra' + ] + path: './apps/staging' + prune: true + retryIntervalInSeconds: 120 + syncIntervalInSeconds: 600 + timeoutInSeconds: 600 + } + infra: { + dependsOn: [] + path: './infrastructure' + prune: true + syncIntervalInSeconds: 600 + timeoutInSeconds: 600 + validation: 'none' + } + } + namespace: 'flux-system-helm' + scope: 'cluster' + } + ] + configurationSettings: { + 'helm-controller.enabled': 'true' + 'image-automation-controller.enabled': 'false' + 'image-reflector-controller.enabled': 'false' + 'kustomize-controller.enabled': 'true' + 'notification-controller.enabled': 'true' + 'source-controller.enabled': 'true' + } +} +param identityProfile = { + kubeletidentity: { + resourceId: '' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param monitoringWorkspaceId = '' +param networkDataplane = 'azure' +param networkPlugin = 'azure' +param networkPluginMode = 'overlay' +param omsAgentEnabled = true +param openServiceMeshEnabled = true +param roleAssignments = [ + { + name: 'ac915208-669e-4665-9792-7e2dc861f569' + 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 only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -690,7 +950,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

via JSON Parameter file +via JSON parameters file ```json { @@ -727,6 +987,33 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmin001' +param primaryAgentPoolProfile = [ + { + count: 3 + mode: 'System' + name: 'systempool' + vmSize: 'Standard_DS2_v2' + } +] +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
+

+ ### Example 4: _Using Kubenet Network Plugin._ This instance deploys the module with Kubenet network plugin . @@ -860,7 +1147,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1003,6 +1290,129 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmkube001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 1 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param networkPlugin = 'kubenet' +param roleAssignments = [ + { + name: '6acf186b-abbd-491b-8bd7-39fa199da81e' + 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: _Using Private Cluster._ This instance deploys the module with a private cluster instance. @@ -1105,7 +1515,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1221,6 +1631,98 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmpriv001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 1 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +param dnsServiceIP = '10.10.200.10' +param enablePrivateCluster = true +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param networkPlugin = 'azure' +param privateDNSZone = '' +param serviceCidr = '10.10.200.0/24' +param skuTier = 'Standard' +``` + +
+

+ ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -1364,7 +1866,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1537,6 +2039,139 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'cswaf001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 3 + enableAutoScaling: true + maxCount: 3 + maxPods: 50 + minCount: 3 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 3 + enableAutoScaling: true + maxCount: 3 + maxPods: 50 + minCount: 3 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 60 + osDiskType: 'Ephemeral' + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } + { + availabilityZones: [ + '3' + ] + count: 3 + enableAutoScaling: true + maxCount: 3 + maxPods: 50 + minCount: 3 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 60 + osDiskType: 'Ephemeral' + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +param autoUpgradeProfileUpgradeChannel = 'stable' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'kube-apiserver' + } + { + category: 'kube-controller-manager' + } + { + category: 'kube-scheduler' + } + { + category: 'cluster-autoscaler' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAccounts = true +param dnsServiceIP = '10.10.200.10' +param enableAzureDefender = true +param enablePrivateCluster = true +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param monitoringWorkspaceId = '' +param networkPlugin = 'azure' +param networkPolicy = 'azure' +param omsAgentEnabled = true +param privateDNSZone = '' +param serviceCidr = '10.10.200.0/24' +param skuTier = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/data-factory/factory/README.md b/avm/res/data-factory/factory/README.md index 4f12df906f..6ac0a9c7ce 100644 --- a/avm/res/data-factory/factory/README.md +++ b/avm/res/data-factory/factory/README.md @@ -65,7 +65,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,22 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -250,7 +266,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -435,6 +451,159 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-factory/factory:' + +// Required parameters +param name = 'dffmax001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gitConfigureLater = true +param globalParameters = { + testParameter1: { + type: 'String' + value: 'testValue1' + } +} +param integrationRuntimes = [ + { + name: 'TestRuntime' + type: 'SelfHosted' + } + { + managedVirtualNetworkName: 'default' + name: 'IRvnetManaged' + type: 'Managed' + typeProperties: { + computeProperties: { + location: 'AutoResolve' + } + } + } +] +param linkedServices = [ + { + name: 'SQLdbLinkedservice' + type: 'AzureSQLDatabase' + typeProperties: { + connectionString: '' + } + } + { + description: 'This is a description for the linked service using the IRvnetManaged integration runtime.' + integrationRuntimeName: 'IRvnetManaged' + name: 'LakeStoreLinkedservice' + parameters: { + storageAccountName: { + defaultValue: 'madeupstorageaccname' + type: 'String' + } + } + type: 'AzureBlobFS' + typeProperties: { + url: '' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param managedPrivateEndpoints = [ + { + fqdns: [ + '' + ] + groupId: 'blob' + name: '' + privateLinkResourceId: '' + } +] +param managedVirtualNetworkName = 'default' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + application: 'AVM' + 'hidden-title': 'This is visible in the resource name' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '12093237-f40a-4f36-868f-accbeebf540c' + 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. @@ -481,7 +650,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -531,6 +700,42 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-factory/factory:' + +// Required parameters +param name = 'dffwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gitConfigureLater = true +param integrationRuntimes = [ + { + name: 'TestRuntime' + type: 'SelfHosted' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/data-protection/backup-vault/README.md b/avm/res/data-protection/backup-vault/README.md index 77172ba563..b0ce4fac62 100644 --- a/avm/res/data-protection/backup-vault/README.md +++ b/avm/res/data-protection/backup-vault/README.md @@ -58,7 +58,7 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-protection/backup-vault:' + +// Required parameters +param name = 'dpbvmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -200,7 +216,7 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +344,116 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-protection/backup-vault:' + +// Required parameters +param name = 'dpbvmax001' +// Non-required parameters +param azureMonitorAlertSettingsAlertsForAllJobFailures = 'Disabled' +param backupPolicies = [ + { + name: 'DefaultPolicy' + properties: { + datasourceTypes: [ + 'Microsoft.Compute/disks' + ] + objectType: 'BackupPolicy' + policyRules: [ + { + backupParameters: { + backupType: 'Incremental' + objectType: 'AzureBackupParams' + } + dataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + name: 'BackupDaily' + objectType: 'AzureBackupRule' + trigger: { + objectType: 'ScheduleBasedTriggerContext' + schedule: { + repeatingTimeIntervals: [ + 'R/2022-05-31T23:30:00+01:00/P1D' + ] + timeZone: 'W. Europe Standard Time' + } + taggingCriteria: [ + { + isDefault: true + taggingPriority: 99 + tagInfo: { + id: 'Default_' + tagName: 'Default' + } + } + ] + } + } + { + isDefault: true + lifecycles: [ + { + deleteAfter: { + duration: 'P7D' + objectType: 'AbsoluteDeleteOption' + } + sourceDataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + targetDataStoreCopySettings: [] + } + ] + name: 'Default' + objectType: 'AzureRetentionRule' + } + ] + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + name: 'cbc3932a-1bee-4318-ae76-d70e1ba399c8' + 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. @@ -429,7 +555,7 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -536,6 +662,97 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-protection/backup-vault:' + +// Required parameters +param name = 'dpbvwaf001' +// Non-required parameters +param azureMonitorAlertSettingsAlertsForAllJobFailures = 'Disabled' +param backupPolicies = [ + { + name: 'DefaultPolicy' + properties: { + datasourceTypes: [ + 'Microsoft.Compute/disks' + ] + objectType: 'BackupPolicy' + policyRules: [ + { + backupParameters: { + backupType: 'Incremental' + objectType: 'AzureBackupParams' + } + dataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + name: 'BackupDaily' + objectType: 'AzureBackupRule' + trigger: { + objectType: 'ScheduleBasedTriggerContext' + schedule: { + repeatingTimeIntervals: [ + 'R/2022-05-31T23:30:00+01:00/P1D' + ] + timeZone: 'W. Europe Standard Time' + } + taggingCriteria: [ + { + isDefault: true + taggingPriority: 99 + tagInfo: { + id: 'Default_' + tagName: 'Default' + } + } + ] + } + } + { + isDefault: true + lifecycles: [ + { + deleteAfter: { + duration: 'P7D' + objectType: 'AbsoluteDeleteOption' + } + sourceDataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + targetDataStoreCopySettings: [] + } + ] + name: 'Default' + objectType: 'AzureRetentionRule' + } + ] + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/databricks/access-connector/README.md b/avm/res/databricks/access-connector/README.md index e825762f75..cc2a54e83b 100644 --- a/avm/res/databricks/access-connector/README.md +++ b/avm/res/databricks/access-connector/README.md @@ -56,7 +56,7 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/access-connector:' + +// Required parameters +param name = 'dacmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -138,7 +154,7 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -202,6 +218,56 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/access-connector:' + +// Required parameters +param name = 'dacmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'e9143a6b-a031-419c-a597-cc4ac9bd39ed' + 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. @@ -240,7 +306,7 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -280,6 +346,34 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/access-connector:' + +// Required parameters +param name = 'dacwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index 5b877cd4ce..927dca6a7e 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -61,7 +61,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,22 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -212,7 +228,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -389,6 +405,125 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/workspace:' + +// Required parameters +param name = 'dwmax002' +// Non-required parameters +param amlWorkspaceResourceId = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param customerManagedKeyManagedDisk = { + keyName: '' + keyVaultResourceId: '' + rotationToLatestKeyVersionEnabled: true +} +param customPrivateSubnetName = '' +param customPublicSubnetName = '' +param customVirtualNetworkResourceId = '' +param defaultCatalog = { + initialType: 'UnityCatalog' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disablePublicIp = true +param loadBalancerBackendPoolName = '' +param loadBalancerResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedResourceGroupResourceId = '' +param natGatewayName = 'nat-gateway' +param prepareEncryption = true +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'databricks_ui_api' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'browser_authentication' + subnetResourceId: '' + } +] +param publicIpName = 'nat-gw-public-ip' +param publicNetworkAccess = 'Disabled' +param requiredNsgRules = 'NoAzureDatabricksRules' +param requireInfrastructureEncryption = true +param roleAssignments = [ + { + name: '2754e64b-b96e-44bc-9cb2-6e39b057f515' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'premium' +param storageAccountName = 'sadwmax001' +param storageAccountSkuName = 'Standard_ZRS' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vnetAddressPrefix = '10.100' +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -500,7 +635,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -661,6 +796,107 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/workspace:' + +// Required parameters +param name = 'dwwaf001' +// Non-required parameters +param accessConnectorResourceId = '' +param amlWorkspaceResourceId = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param customerManagedKeyManagedDisk = { + keyName: '' + keyVaultResourceId: '' + rotationToLatestKeyVersionEnabled: true +} +param customPrivateSubnetName = '' +param customPublicSubnetName = '' +param customVirtualNetworkResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disablePublicIp = true +param loadBalancerBackendPoolName = '' +param loadBalancerResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedResourceGroupResourceId = '' +param natGatewayName = 'nat-gateway' +param prepareEncryption = true +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'databricks_ui_api' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param privateStorageAccount = 'Enabled' +param publicIpName = 'nat-gw-public-ip' +param publicNetworkAccess = 'Disabled' +param requiredNsgRules = 'NoAzureDatabricksRules' +param requireInfrastructureEncryption = true +param skuName = 'premium' +param storageAccountName = 'sadwwaf001' +param storageAccountPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param storageAccountSkuName = 'Standard_ZRS' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vnetAddressPrefix = '10.100' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/db-for-my-sql/flexible-server/README.md b/avm/res/db-for-my-sql/flexible-server/README.md index dbe135fbc5..428d5be284 100644 --- a/avm/res/db-for-my-sql/flexible-server/README.md +++ b/avm/res/db-for-my-sql/flexible-server/README.md @@ -66,7 +66,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

-via JSON Parameter file +via JSON parameters file ```json { @@ -103,6 +103,27 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmsfsmin001' +param skuName = 'Standard_D2ds_v4' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param location = '' +param storageAutoGrow = 'Enabled' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -227,7 +248,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

-via JSON Parameter file +via JSON parameters file ```json { @@ -391,6 +412,120 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmsmax001' +param skuName = 'Standard_D2ads_v5' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param availabilityZone = '1' +param backupRetentionDays = 20 +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param customerManagedKeyGeo = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param databases = [ + { + name: 'testdb1' + } + { + charset: 'ascii' + collation: 'ascii_general_ci' + name: 'testdb2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallRules = [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } + { + endIpAddress: '10.10.10.10' + name: 'test-rule1' + startIpAddress: '10.10.10.1' + } + { + endIpAddress: '100.100.100.10' + name: 'test-rule2' + startIpAddress: '100.100.100.1' + } +] +param geoRedundantBackup = 'Enabled' +param highAvailability = 'ZoneRedundant' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + '' + ] +} +param roleAssignments = [ + { + name: '2478b63b-0cae-457f-9bd3-9feb00e1925b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageAutoGrow = 'Enabled' +param storageAutoIoScaling = 'Enabled' +param storageIOPS = 400 +param storageSizeGB = 64 +param tags = { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'MySQL Flexible Server' + serverName: 'dfmsmax001' +} +param version = '8.0.21' +``` + +
+

+ ### Example 3: _Deploys in connectivity mode "Private Access"_ This instance deploys the module with connectivity mode "Private Access". @@ -446,7 +581,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

-via JSON Parameter file +via JSON parameters file ```json { @@ -527,6 +662,51 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmspvt001' +param skuName = 'Standard_D2ds_v4' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param administrators = [ + { + identityResourceId: '' + login: '' + sid: '' + } +] +param backupRetentionDays = 10 +param databases = [ + { + name: 'testdb1' + } +] +param delegatedSubnetResourceId = '' +param highAvailability = 'SameZone' +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param privateDnsZoneResourceId = '' +param storageAutoGrow = 'Enabled' +param storageAutoIoScaling = 'Enabled' +param storageIOPS = 400 +param storageSizeGB = 64 +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -570,7 +750,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

-via JSON Parameter file +via JSON parameters file ```json { @@ -629,6 +809,39 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmswaf001' +param skuName = 'Standard_D2ds_v4' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param availabilityZone = '1' +param highAvailability = 'ZoneRedundant' +param highAvailabilityZone = '2' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param storageAutoGrow = 'Enabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md index c60b6026b4..ec83051aaa 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/README.md +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -74,7 +74,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

via JSON Parameter file +via JSON parameters file ```json { @@ -117,6 +117,33 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfsmin001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administrators = [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } +] +param geoRedundantBackup = 'Enabled' +param highAvailability = 'ZoneRedundant' +param location = '' +``` + +
+

+ ### Example 2: _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. @@ -157,7 +184,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

via JSON Parameter file +via JSON parameters file ```json { @@ -205,6 +232,36 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfse001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +``` + +
+

+ ### Example 3: _Private access_ This instance deploys the module with private access only. @@ -296,7 +353,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

via JSON Parameter file +via JSON parameters file ```json { @@ -407,6 +464,87 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfspvt001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param configurations = [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } +] +param databases = [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } +] +param delegatedSubnetResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param geoRedundantBackup = 'Enabled' +param location = '' +param privateDnsZoneArmResourceId = '' +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 4: _Public access_ This instance deploys the module with public access. @@ -517,7 +655,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

via JSON Parameter file +via JSON parameters file ```json { @@ -651,6 +789,106 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfsp001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administrators = [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } +] +param backupRetentionDays = 20 +param configurations = [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } +] +param databases = [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallRules = [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } + { + endIpAddress: '10.10.10.10' + name: 'test-rule1' + startIpAddress: '10.10.10.1' + } + { + endIpAddress: '100.100.100.10' + name: 'test-rule2' + startIpAddress: '100.100.100.1' + } +] +param geoRedundantBackup = 'Disabled' +param highAvailability = 'SameZone' +param location = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageSizeGB = 1024 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param version = '14' +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -731,7 +969,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

via JSON Parameter file +via JSON parameters file ```json { @@ -831,6 +1069,76 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfswaf001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administrators = [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } +] +param configurations = [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } +] +param databases = [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } +] +param delegatedSubnetResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param geoRedundantBackup = 'Enabled' +param highAvailability = 'ZoneRedundant' +param location = '' +param maintenanceWindow = { + customWindow: 'Enabled' + dayOfWeek: 0 + startHour: 1 + startMinute: 0 +} +param privateDnsZoneArmResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/desktop-virtualization/application-group/README.md b/avm/res/desktop-virtualization/application-group/README.md index da9a322e54..2ece1d6fa8 100644 --- a/avm/res/desktop-virtualization/application-group/README.md +++ b/avm/res/desktop-virtualization/application-group/README.md @@ -60,7 +60,7 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

-via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,24 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

+

+ +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. @@ -177,7 +195,7 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

-via JSON Parameter file +via JSON parameters file ```json { @@ -278,6 +296,85 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

+

+ +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. @@ -318,7 +415,7 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

-via JSON Parameter file +via JSON parameters file ```json { @@ -362,6 +459,36 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

+

+ +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** diff --git a/avm/res/desktop-virtualization/host-pool/README.md b/avm/res/desktop-virtualization/host-pool/README.md index 886a58e81a..094d7b8fad 100644 --- a/avm/res/desktop-virtualization/host-pool/README.md +++ b/avm/res/desktop-virtualization/host-pool/README.md @@ -60,7 +60,7 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

+

+ +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. @@ -213,7 +229,7 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -372,6 +388,127 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

+

+ +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. @@ -411,7 +548,7 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -450,6 +587,35 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

+

+ +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** diff --git a/avm/res/desktop-virtualization/scaling-plan/README.md b/avm/res/desktop-virtualization/scaling-plan/README.md index 97207ef73c..4482d692f6 100644 --- a/avm/res/desktop-virtualization/scaling-plan/README.md +++ b/avm/res/desktop-virtualization/scaling-plan/README.md @@ -57,7 +57,7 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan: -

via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:

+

+ +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. @@ -263,7 +279,7 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan: -

via JSON Parameter file +via JSON parameters file ```json { @@ -459,6 +475,180 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:

+

+ +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. @@ -500,7 +690,7 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan: -

via JSON Parameter file +via JSON parameters file ```json { @@ -545,6 +735,37 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:

+

+ +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** diff --git a/avm/res/desktop-virtualization/workspace/README.md b/avm/res/desktop-virtualization/workspace/README.md index c71da4bcbb..bc71f372f4 100644 --- a/avm/res/desktop-virtualization/workspace/README.md +++ b/avm/res/desktop-virtualization/workspace/README.md @@ -60,7 +60,7 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

+

+ +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. @@ -231,7 +247,7 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -392,6 +408,145 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

+

+ +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. @@ -431,7 +586,7 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -470,6 +625,35 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

+

+ +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** diff --git a/avm/res/dev-ops-infrastructure/pool/README.md b/avm/res/dev-ops-infrastructure/pool/README.md index 4ea945d1ab..dee3ec1d9f 100644 --- a/avm/res/dev-ops-infrastructure/pool/README.md +++ b/avm/res/dev-ops-infrastructure/pool/README.md @@ -77,7 +77,7 @@ module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -130,6 +130,41 @@ module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/dev-ops-infrastructure/pool:' + +// Required parameters +param agentProfile = { + kind: 'Stateless' +} +param concurrency = 1 +param devCenterProjectResourceId = '' +param fabricProfileSkuName = 'Standard_DS2_v2' +param images = [ + { + wellKnownImageName: 'windows-2022/latest' + } +] +param name = 'mdpmin001' +param organizationProfile = { + kind: 'AzureDevOps' + organizations: [ + { + url: '' + } + ] +} +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -246,7 +281,7 @@ module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -380,6 +415,112 @@ module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/dev-ops-infrastructure/pool:' + +// Required parameters +param agentProfile = { + kind: 'Stateless' + resourcePredictions: { + daysData: [ + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + {} + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + ] + timeZone: 'Central Europe Standard Time' + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } +} +param concurrency = 1 +param devCenterProjectResourceId = '' +param fabricProfileSkuName = 'Standard_D2_v2' +param images = [ + { + aliases: [ + 'windows-2022' + ] + buffer: '*' + wellKnownImageName: 'windows-2022/latest' + } +] +param name = 'mdpmax001' +param organizationProfile = { + kind: 'AzureDevOps' + organizations: [ + { + parallelism: 1 + projects: [ + '' + ] + url: '' + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } +} +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } +] +param storageProfile = { + dataDisks: [ + { + caching: 'ReadWrite' + diskSizeGiB: 100 + driveLetter: 'B' + storageAccountType: 'Standard_LRS' + } + ] + osDiskStorageAccountType: 'Standard' +} +param subnetResourceId = '' +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. @@ -455,7 +596,7 @@ module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -540,6 +681,71 @@ module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/dev-ops-infrastructure/pool:' + +// Required parameters +param agentProfile = { + kind: 'Stateless' + resourcePredictions: { + daysData: [ + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + {} + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + ] + timeZone: 'Central Europe Standard Time' + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } +} +param concurrency = 1 +param devCenterProjectResourceId = '' +param fabricProfileSkuName = 'Standard_D2_v2' +param images = [ + { + wellKnownImageName: 'windows-2022/latest' + } +] +param name = 'mdpwaf001' +param organizationProfile = { + kind: 'AzureDevOps' + organizations: [ + { + parallelism: 1 + projects: [ + '' + ] + url: '' + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } +} +// Non-required parameters +param location = '' +param subnetResourceId = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/digital-twins/digital-twins-instance/README.md b/avm/res/digital-twins/digital-twins-instance/README.md index 17f002c774..1cb5feb1f6 100644 --- a/avm/res/digital-twins/digital-twins-instance/README.md +++ b/avm/res/digital-twins/digital-twins-instance/README.md @@ -59,7 +59,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

-via JSON Parameter file +via JSON parameters file ```json { @@ -76,6 +76,19 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +param name = 'dtdimin001' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -192,7 +205,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

-via JSON Parameter file +via JSON parameters file ```json { @@ -322,6 +335,112 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +// Required parameters +param name = 'dtdmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventGridEndpoints = [ + { + eventGridDomainId: '' + topicEndpoint: '' + } +] +param eventHubEndpoints = [ + { + authenticationType: 'IdentityBased' + endpointUri: '' + entityPath: '' + managedIdentities: { + userAssignedResourceId: '' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param serviceBusEndpoints = [ + { + authenticationType: 'IdentityBased' + endpointUri: '' + entityPath: '' + managedIdentities: { + userAssignedResourceId: '' + } + name: 'ServiceBusPrimary' + } + { + authenticationType: 'IdentityBased' + endpointUri: '' + entityPath: '' + managedIdentities: { + systemAssigned: true + } + name: 'ServiceBusSeconday' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 3: _Using private endpoint parameter set_ This instance deploys the module with idempotancy tests for private endpoints. @@ -362,7 +481,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

-via JSON Parameter file +via JSON parameters file ```json { @@ -400,6 +519,36 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +// Required parameters +param name = 'dtdpep001' +// Non-required parameters +param location = '' +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -439,7 +588,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

-via JSON Parameter file +via JSON parameters file ```json { @@ -478,6 +627,35 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +// Required parameters +param name = 'dtdiwaf001' +// 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** diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md index e3b1d30fb6..44848ebee3 100644 --- a/avm/res/document-db/database-account/README.md +++ b/avm/res/document-db/database-account/README.md @@ -85,7 +85,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -117,6 +117,28 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'analytical' +// Non-required parameters +param enableAnalyticalStorage = true +param location = '' +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
+

+ ### Example 2: _Using bounded consistency_ This instance deploys the module specifying a default consistency level. @@ -151,7 +173,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -189,6 +211,30 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'bounded' +// Non-required parameters +param defaultConsistencyLevel = 'BoundedStaleness' +param location = '' +param maxIntervalInSeconds = 600 +param maxStalenessPrefix = 200000 +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
+

+ ### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -215,7 +261,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -237,6 +283,22 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

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

+ ### Example 4: _Gremlin Database_ This instance deploys the module with a Gremlin Database. @@ -367,7 +429,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -507,6 +569,126 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddagrm002' +// Non-required parameters +param capabilitiesToAdd = [ + 'EnableGremlin' +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gremlinDatabases = [ + { + graphs: [ + { + indexingPolicy: { + automatic: true + } + name: 'car_collection' + partitionKeyPaths: [ + '/car_id' + ] + } + { + indexingPolicy: { + automatic: true + } + name: 'truck_collection' + partitionKeyPaths: [ + '/truck_id' + ] + } + ] + name: 'gdb-dddagrm-001' + throughput: 10000 + } + { + graphs: [ + { + indexingPolicy: { + automatic: true + } + name: 'bike_collection' + partitionKeyPaths: [ + '/bike_id' + ] + } + { + indexingPolicy: { + automatic: true + } + name: 'bicycle_collection' + partitionKeyPaths: [ + '/bicycle_id' + ] + } + ] + name: 'gdb-dddagrm-002' + } +] +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } + { + failoverPriority: 1 + isZoneRedundant: false + locationName: '' + } +] +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + 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: _Deploying with a key vault reference to save secrets_ This instance deploys the module saving all its secrets in a key vault. @@ -544,7 +726,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -579,6 +761,33 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'kv-ref' +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + keyVaultResourceId: '' + primaryReadonlyConnectionStringSecretName: 'primaryReadonlyConnectionString' + primaryReadOnlyKeySecretName: 'primaryReadOnlyKey' + primaryWriteConnectionStringSecretName: 'primaryWriteConnectionString' + primaryWriteKeySecretName: 'primaryWriteKey' + secondaryReadonlyConnectionStringSecretName: 'secondaryReadonlyConnectionString' + secondaryReadonlyKeySecretName: 'secondaryReadonlyKey' + secondaryWriteConnectionStringSecretName: 'secondaryWriteConnectionString' + secondaryWriteKeySecretName: 'secondaryWriteKey' +} +``` + +
+

+ ### Example 6: _Deploying with Managed identities_ This instance deploys the module with an system and user assigned managed identity. @@ -629,7 +838,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -679,6 +888,46 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'user-mi' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
+

+ ### Example 7: _Mongo Database_ This instance deploys the module with a Mongo Database. @@ -943,7 +1192,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1215,6 +1464,260 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddamng001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } + { + failoverPriority: 1 + isZoneRedundant: false + locationName: '' + } +] +param managedIdentities = { + systemAssigned: true +} +param mongodbDatabases = [ + { + collections: [ + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'car_id' + 'car_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'car_collection' + shardKey: { + car_id: 'Hash' + } + throughput: 600 + } + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'truck_id' + 'truck_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'truck_collection' + shardKey: { + truck_id: 'Hash' + } + } + ] + name: 'mdb-dddamng-001' + throughput: 800 + } + { + collections: [ + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'bike_id' + 'bike_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'bike_collection' + shardKey: { + bike_id: 'Hash' + } + } + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'bicycle_id' + 'bicycle_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'bicycle_collection' + shardKey: { + bicycle_id: 'Hash' + } + } + ] + name: 'mdb-dddamng-002' + } +] +param roleAssignments = [ + { + 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 8: _Deploying multiple regions_ This instance deploys the module in multiple regions with configs specific of multi region scenarios. @@ -1264,7 +1767,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1325,6 +1828,45 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'multi-region' +// Non-required parameters +param automaticFailover = false +param backupIntervalInMinutes = 300 +param backupPolicyType = 'Periodic' +param backupRetentionIntervalInHours = 16 +param backupStorageRedundancy = 'Zone' +param enableMultipleWriteLocations = true +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: true + locationName: '' + } + { + failoverPriority: 1 + isZoneRedundant: true + locationName: '' + } +] +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
+

+ ### Example 9: _Plain_ This instance deploys the module without a Database. @@ -1368,7 +1910,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1421,6 +1963,39 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddapln001' +// Non-required parameters +param backupPolicyContinuousTier = 'Continuous7Days' +param backupPolicyType = 'Continuous' +param defaultConsistencyLevel = 'ConsistentPrefix' +param disableKeyBasedMetadataWriteAccess = true +param disableLocalAuth = true +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } +] +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
+

+ ### Example 10: _Public network restricted access with ACL_ This instance deploys the module with public network access enabled but restricted to IPs, CIDRS or subnets. @@ -1465,7 +2040,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1509,6 +2084,40 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddapres001' +// Non-required parameters +param location = '' +param networkRestrictions = { + ipRules: [ + '79.0.0.0' + '80.0.0.0' + ] + networkAclBypass: 'AzureServices' + publicNetworkAccess: 'Enabled' + virtualNetworkRules: [ + { + subnetResourceId: '' + } + ] +} +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
+

+ ### Example 11: _Deploying with a sql role definision and assignment_ This instance deploys the module with sql role definision and assignment @@ -1543,7 +2152,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1577,6 +2186,30 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'role-ref' +// Non-required parameters +param location = '' +param sqlRoleAssignmentsPrincipalIds = [ + '' +] +param sqlRoleDefinitions = [ + { + name: 'cosmos-sql-role-test' + } +] +``` + +
+

+ ### Example 12: _SQL Database_ This instance deploys the module with a SQL Database. @@ -1861,7 +2494,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -2147,6 +2780,280 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddasql001' +// Non-required parameters +param enableAnalyticalStorage = true +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } +] +param sqlDatabases = [ + { + containers: [ + { + analyticalStorageTtl: 0 + conflictResolutionPolicy: { + conflictResolutionPath: '/myCustomId' + mode: 'LastWriterWins' + } + defaultTtl: 1000 + indexingPolicy: { + automatic: true + } + kind: 'Hash' + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + throughput: 600 + uniqueKeyPolicyKeys: [ + { + paths: [ + '/firstName' + ] + } + { + paths: [ + '/lastName' + ] + } + ] + } + ] + name: 'all-configs-specified' + } + { + containers: [ + { + indexingPolicy: { + automatic: true + } + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'automatic-indexing-policy' + } + { + containers: [ + { + conflictResolutionPolicy: { + conflictResolutionPath: '/myCustomId' + mode: 'LastWriterWins' + } + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'last-writer-conflict-resolution-policy' + } + { + containers: [ + { + analyticalStorageTtl: 1000 + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'fixed-analytical-ttl' + } + { + containers: [ + { + analyticalStorageTtl: -1 + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'infinite-analytical-ttl' + } + { + containers: [ + { + defaultTtl: 1000 + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'document-ttl' + } + { + containers: [ + { + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + uniqueKeyPolicyKeys: [ + { + paths: [ + '/firstName' + ] + } + { + paths: [ + '/lastName' + ] + } + ] + } + ] + name: 'unique-key-policy' + } + { + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + throughput: 500 + } + ] + name: 'db-and-container-fixed-throughput-level' + throughput: 500 + } + { + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + throughput: 500 + } + ] + name: 'container-fixed-throughput-level' + } + { + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'database-fixed-throughput-level' + throughput: 500 + } + { + autoscaleSettingsMaxThroughput: 1000 + containers: [ + { + autoscaleSettingsMaxThroughput: 1000 + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'db-and-container-autoscale-level' + } + { + containers: [ + { + autoscaleSettingsMaxThroughput: 1000 + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'container-autoscale-level' + } + { + autoscaleSettingsMaxThroughput: 1000 + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'database-autoscale-level' + } + { + containers: [ + { + kind: 'MultiHash' + name: 'container-001' + paths: [ + '/myPartitionKey1' + '/myPartitionKey2' + '/myPartitionKey3' + ] + } + { + kind: 'MultiHash' + name: 'container-002' + paths: [ + 'myPartitionKey1' + 'myPartitionKey2' + 'myPartitionKey3' + ] + } + { + kind: 'Hash' + name: 'container-003' + paths: [ + '/myPartitionKey1' + ] + } + { + kind: 'Hash' + name: 'container-004' + paths: [ + 'myPartitionKey1' + ] + } + { + kind: 'Hash' + name: 'container-005' + paths: [ + 'myPartitionKey1' + ] + version: 2 + } + ] + name: 'all-partition-key-types' + } + { + containers: [] + name: 'empty-containers-array' + } + { + name: 'no-containers-specified' + } +] +``` + +
+

+ ### Example 13: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -2223,7 +3130,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

-via JSON Parameter file +via JSON parameters file ```json { @@ -2307,6 +3214,72 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddawaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableKeyBasedMetadataWriteAccess = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Sql' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sqlDatabases = [ + { + containers: [ + { + kind: 'Hash' + name: 'container-001' + paths: [ + '/myPartitionKey1' + ] + } + ] + name: 'sql-dddawaf-001' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/document-db/mongo-cluster/README.md b/avm/res/document-db/mongo-cluster/README.md index c4af03e2b4..2ebb5f8479 100644 --- a/avm/res/document-db/mongo-cluster/README.md +++ b/avm/res/document-db/mongo-cluster/README.md @@ -70,7 +70,7 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -107,6 +107,27 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin001' +param administratorLoginPassword = '' +param name = 'ddmcdefmin001' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Deploying with a key vault reference to save secrets_ This instance deploys the module saving its secrets in a key vault. @@ -142,7 +163,7 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -185,6 +206,31 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin002' +param administratorLoginPassword = '' +param name = 'kv-ref' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + connectionStringSecretName: 'connectionString' + keyVaultResourceId: '' +} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with the maximum set of required parameters. @@ -290,7 +336,7 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -415,6 +461,101 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin003' +param administratorLoginPassword = '' +param name = 'ddmcmax001' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param createMode = 'Default' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param highAvailabilityMode = false +param location = '' +param networkAcls = { + allowAllIPs: true + allowAzureIPs: true + customRules: [ + { + endIpAddress: '5.6.7.8' + firewallRuleName: 'allow-1.2.3.4-to-5.6.7.8' + startIpAddress: '1.2.3.4' + } + ] +} +param nodeType = 'Shard' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -446,7 +587,7 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -483,6 +624,27 @@ module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin001' +param administratorLoginPassword = '' +param name = 'ddmcwaf001' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param location = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/event-grid/domain/README.md b/avm/res/event-grid/domain/README.md index a9833d9025..7e0ec765a4 100644 --- a/avm/res/event-grid/domain/README.md +++ b/avm/res/event-grid/domain/README.md @@ -61,7 +61,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,22 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/domain:' + +// Required parameters +param name = 'egdmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -187,7 +203,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -301,6 +317,100 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/domain:' + +// Required parameters +param name = 'egdmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundIpRules = [ + { + action: 'Allow' + ipMask: '40.74.28.0/23' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '1d2dba39-c8fe-45f9-a3af-6dc15caa95a5' + 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 topics = [ + 'topic-egdmax001' +] +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -372,7 +482,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -451,6 +561,67 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/domain:' + +// Required parameters +param name = 'egdwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundIpRules = [] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'domain' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + 'topic-egdwaf001' +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/event-grid/namespace/README.md b/avm/res/event-grid/namespace/README.md index 7ac321334d..68fe8bf4f3 100644 --- a/avm/res/event-grid/namespace/README.md +++ b/avm/res/event-grid/namespace/README.md @@ -69,7 +69,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -91,6 +91,22 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -299,7 +315,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -517,6 +533,204 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'bde32b53-e30c-41d0-a338-c637853fe524' + 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 topics = [ + { + eventRetentionInDays: 7 + eventSubscriptions: [ + { + deliveryConfiguration: { + deliveryMode: 'Queue' + queue: { + eventTimeToLive: 'P7D' + maxDeliveryCount: 10 + receiveLockDurationInSeconds: 60 + } + } + name: 'subscription1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + deliveryConfiguration: { + deliveryMode: 'Push' + push: { + deliveryWithResourceIdentity: { + destination: { + endpointType: 'EventHub' + properties: { + deliveryAttributeMappings: [ + { + name: 'StaticHeader1' + properties: { + isSecret: false + value: 'staticVaule' + } + type: 'Static' + } + { + name: 'DynamicHeader1' + properties: { + sourceField: 'id' + } + type: 'Dynamic' + } + { + name: 'StaticSecretHeader1' + properties: { + isSecret: true + value: 'Hidden' + } + type: 'Static' + } + ] + resourceId: '' + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentity: '' + } + } + eventTimeToLive: 'P7D' + maxDeliveryCount: 10 + } + } + name: 'subscription2' + } + ] + name: 'topic1' + } + { + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + name: 'topic2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +``` + +
+

+ ### Example 3: _MQTT Broker with routing to a namespace topic_ This instance deploys the module as a MQTT Broker with routing to a topic within the same Eventgrid namespace. @@ -674,7 +888,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -853,6 +1067,153 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmqttct001' +// Non-required parameters +param alternativeAuthenticationNameSources = [ + 'ClientCertificateEmail' + 'ClientCertificateUri' +] +param clientGroups = [ + { + description: 'this is group1' + name: 'group1' + query: 'attributes.keyName IN [\'a\', \'b\', \'c\']' + } +] +param clients = [ + { + attributes: { + deviceTypes: [ + 'Fan' + 'Light' + ] + floor: 12 + room: '345' + } + authenticationName: 'client2auth' + clientCertificateAuthenticationAllowedThumbprints: [ + '1111111111111111111111111111111111111111' + '2222222222222222222222222222222222222222' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + description: 'this is client2' + name: 'client1' + state: 'Enabled' + } + { + clientCertificateAuthenticationAllowedThumbprints: [ + '3333333333333333333333333333333333333333' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + name: 'client2' + } + { + name: 'client3' + } + { + clientCertificateAuthenticationValidationSchema: 'IpMatchesAuthenticationName' + name: 'client4' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param maximumClientSessionsPerAuthenticationName = 5 +param maximumSessionExpiryInHours = 2 +param permissionBindings = [ + { + clientGroupName: 'group1' + description: 'this is binding1' + name: 'bindiing1' + permission: 'Publisher' + topicSpaceName: 'topicSpace1' + } + { + clientGroupName: 'group1' + name: 'bindiing2' + permission: 'Subscriber' + topicSpaceName: 'topicSpace2' + } +] +param routeTopicResourceId = '' +param routingEnrichments = { + dynamic: [ + { + key: 'dynamic1' + value: '' + } + ] + static: [ + { + key: 'static1' + value: 'value1' + valueType: 'String' + } + { + key: 'static2' + value: 'value2' + valueType: 'String' + } + ] +} +param routingIdentityInfo = { + type: 'UserAssigned' + userAssignedIdentity: '' +} +param topics = [ + { + name: 'topic1' + } +] +param topicSpaces = [ + { + name: 'topicSpace1' + topicTemplates: [ + 'devices/foo/bar' + 'devices/topic1/+' + ] + } + { + name: 'topicSpace2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + topicTemplates: [ + 'devices/topic1/+' + ] + } +] +param topicSpacesState = 'Enabled' +``` + +
+

+ ### Example 4: _MQTT Broker with routing to a namespace topic_ This instance deploys the module as a MQTT Broker with routing to a topic within the same Eventgrid namespace. @@ -1010,7 +1371,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1189,6 +1550,153 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmqttnt001' +// Non-required parameters +param alternativeAuthenticationNameSources = [ + 'ClientCertificateEmail' + 'ClientCertificateUri' +] +param clientGroups = [ + { + description: 'this is group1' + name: 'group1' + query: 'attributes.keyName IN [\'a\', \'b\', \'c\']' + } +] +param clients = [ + { + attributes: { + deviceTypes: [ + 'Fan' + 'Light' + ] + floor: 12 + room: '345' + } + authenticationName: 'client2auth' + clientCertificateAuthenticationAllowedThumbprints: [ + '1111111111111111111111111111111111111111' + '2222222222222222222222222222222222222222' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + description: 'this is client2' + name: 'client1' + state: 'Enabled' + } + { + clientCertificateAuthenticationAllowedThumbprints: [ + '3333333333333333333333333333333333333333' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + name: 'client2' + } + { + name: 'client3' + } + { + clientCertificateAuthenticationValidationSchema: 'IpMatchesAuthenticationName' + name: 'client4' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param maximumClientSessionsPerAuthenticationName = 5 +param maximumSessionExpiryInHours = 2 +param permissionBindings = [ + { + clientGroupName: 'group1' + description: 'this is binding1' + name: 'bindiing1' + permission: 'Publisher' + topicSpaceName: 'topicSpace1' + } + { + clientGroupName: 'group1' + name: 'bindiing2' + permission: 'Subscriber' + topicSpaceName: 'topicSpace2' + } +] +param routeTopicResourceId = '' +param routingEnrichments = { + dynamic: [ + { + key: 'dynamic1' + value: '' + } + ] + static: [ + { + key: 'static1' + value: 'value1' + valueType: 'String' + } + { + key: 'static2' + value: 'value2' + valueType: 'String' + } + ] +} +param routingIdentityInfo = { + type: 'UserAssigned' + userAssignedIdentity: '' +} +param topics = [ + { + name: 'topic1' + } +] +param topicSpaces = [ + { + name: 'topicSpace1' + topicTemplates: [ + 'devices/foo/bar' + 'devices/topic1/+' + ] + } + { + name: 'topicSpace2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + topicTemplates: [ + 'devices/topic1/+' + ] + } +] +param topicSpacesState = 'Enabled' +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1272,7 +1780,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1359,6 +1867,79 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +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** diff --git a/avm/res/event-grid/system-topic/README.md b/avm/res/event-grid/system-topic/README.md index 98c9a44742..51fd97f169 100644 --- a/avm/res/event-grid/system-topic/README.md +++ b/avm/res/event-grid/system-topic/README.md @@ -60,7 +60,7 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,24 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/system-topic:' + +// Required parameters +param name = 'egstmin001' +param source = '' +param topicType = 'Microsoft.Storage.StorageAccounts' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -184,7 +202,7 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -292,6 +310,92 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/system-topic:' + +// Required parameters +param name = 'egstmax001' +param source = '' +param topicType = 'Microsoft.Storage.StorageAccounts' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egstmax001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + name: 'c9beca28-efcf-4d1d-99aa-8f334484a2c2' + 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. @@ -366,7 +470,7 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -448,6 +552,70 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/system-topic:' + +// Required parameters +param name = 'egstwaf001' +param source = '' +param topicType = 'Microsoft.Storage.StorageAccounts' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egstwaf001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +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** diff --git a/avm/res/event-grid/topic/README.md b/avm/res/event-grid/topic/README.md index bf85377cfe..fcb7a52ee0 100644 --- a/avm/res/event-grid/topic/README.md +++ b/avm/res/event-grid/topic/README.md @@ -61,7 +61,7 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,22 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/topic:' + +// Required parameters +param name = 'egtmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -219,7 +235,7 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -365,6 +381,132 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/topic:' + +// Required parameters +param name = 'egtmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egtmax001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +param inboundIpRules = [ + { + action: 'Allow' + ipMask: '40.74.28.0/23' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + 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: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'f80d2f24-53f6-41b3-811f-668b2273dcf8' + 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. @@ -456,7 +598,7 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -555,6 +697,87 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/topic:' + +// Required parameters +param name = 'egtwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egtwaf001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +param inboundIpRules = [] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'topic' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/event-hub/namespace/README.md b/avm/res/event-hub/namespace/README.md index c32df1eeb0..03faa22348 100644 --- a/avm/res/event-hub/namespace/README.md +++ b/avm/res/event-hub/namespace/README.md @@ -67,7 +67,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,22 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnmin001' +// 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. @@ -128,7 +144,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -171,6 +187,35 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnenc001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param requireInfrastructureEncryption = true +param skuName = 'Premium' +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -370,7 +415,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -601,6 +646,195 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnmax001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param eventhubs = [ + { + name: 'az-evh-x-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } + ] + captureDescriptionDestinationArchiveNameFormat: '{Namespace}/{EventHub}/{PartitionId}/{Year}/{Month}/{Day}/{Hour}/{Minute}/{Second}' + captureDescriptionDestinationBlobContainer: 'eventhub' + captureDescriptionDestinationName: 'EventHubArchive.AzureBlockBlob' + captureDescriptionDestinationStorageAccountResourceId: '' + captureDescriptionEnabled: true + captureDescriptionEncoding: 'Avro' + captureDescriptionIntervalInSeconds: 300 + captureDescriptionSizeLimitInBytes: 314572800 + captureDescriptionSkipEmptyArchives: true + consumergroups: [ + { + name: 'custom' + userMetadata: 'customMetadata' + } + ] + messageRetentionInDays: 1 + name: 'az-evh-x-002' + partitionCount: 2 + retentionDescriptionCleanupPolicy: 'Delete' + retentionDescriptionRetentionTimeInHours: 3 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + status: 'Active' + } + { + name: 'az-evh-x-003' + retentionDescriptionCleanupPolicy: 'Compact' + retentionDescriptionTombstoneRetentionTimeInHours: 24 + } +] +param isAutoInflateEnabled = true +param kafkaEnabled = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param maximumThroughputUnits = 4 +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.10.10.10' + } + ] + publicNetworkAccess: 'Disabled' + trustedServiceAccessEnabled: false + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: 'bd0f41e3-8e3e-4cd3-b028-edd61608bd9f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 2 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneRedundant = true +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -754,7 +988,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -931,6 +1165,149 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnwaf001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param eventhubs = [ + { + name: 'az-evh-x-001' + } + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } + ] + captureDescriptionDestinationArchiveNameFormat: '{Namespace}/{EventHub}/{PartitionId}/{Year}/{Month}/{Day}/{Hour}/{Minute}/{Second}' + captureDescriptionDestinationBlobContainer: 'eventhub' + captureDescriptionDestinationName: 'EventHubArchive.AzureBlockBlob' + captureDescriptionDestinationStorageAccountResourceId: '' + captureDescriptionEnabled: true + captureDescriptionEncoding: 'Avro' + captureDescriptionIntervalInSeconds: 300 + captureDescriptionSizeLimitInBytes: 314572800 + captureDescriptionSkipEmptyArchives: true + consumergroups: [ + { + name: 'custom' + userMetadata: 'customMetadata' + } + ] + messageRetentionInDays: 1 + name: 'az-evh-x-002' + partitionCount: 2 + retentionDescriptionCleanupPolicy: 'Delete' + retentionDescriptionRetentionTimeInHours: 3 + status: 'Active' + } + { + name: 'az-evh-x-003' + retentionDescriptionCleanupPolicy: 'Compact' + retentionDescriptionTombstoneRetentionTimeInHours: 24 + } +] +param isAutoInflateEnabled = true +param kafkaEnabled = true +param location = '' +param maximumThroughputUnits = 4 +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.10.10.10' + } + ] + trustedServiceAccessEnabled: false + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Disabled' +param skuCapacity = 2 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/health-bot/health-bot/README.md b/avm/res/health-bot/health-bot/README.md index b23485fd1c..073a60ffba 100644 --- a/avm/res/health-bot/health-bot/README.md +++ b/avm/res/health-bot/health-bot/README.md @@ -62,7 +62,7 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,23 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/health-bot/health-bot:' + +// Required parameters +param name = 'hbhbmin002' +param sku = 'F0' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -147,7 +164,7 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -213,6 +230,56 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/health-bot/health-bot:' + +// Required parameters +param name = 'hbhbmax002' +param sku = 'F0' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '9d89b5ea-0d1f-41d8-9297-52529827d712' + 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. @@ -249,7 +316,7 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -287,6 +354,32 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/health-bot/health-bot:' + +// Required parameters +param name = 'hbhbwaf002' +param sku = 'F0' +// 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** diff --git a/avm/res/healthcare-apis/workspace/README.md b/avm/res/healthcare-apis/workspace/README.md index 992cee3c23..66c2b983fa 100644 --- a/avm/res/healthcare-apis/workspace/README.md +++ b/avm/res/healthcare-apis/workspace/README.md @@ -67,7 +67,7 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,22 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -244,7 +260,7 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -407,6 +423,151 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/healthcare-apis/workspace:' + +// Required parameters +param name = 'hawmax001' +// Non-required parameters +param dicomservices = [ + { + corsAllowCredentials: false + corsHeaders: [ + '*' + ] + corsMaxAge: 600 + corsMethods: [ + 'GET' + ] + corsOrigins: [ + '*' + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + name: 'az-dicom-x-001' + publicNetworkAccess: 'Enabled' + workspaceName: 'hawmax001' + } +] +param fhirservices = [ + { + corsAllowCredentials: false + corsHeaders: [ + '*' + ] + corsMaxAge: 600 + corsMethods: [ + 'GET' + ] + corsOrigins: [ + '*' + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + importEnabled: false + initialImportMode: false + kind: 'fhir-R4' + location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + name: 'az-fhir-x-001' + publicNetworkAccess: 'Enabled' + resourceVersionPolicy: 'versioned' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + smartProxyEnabled: false + workspaceName: 'hawmax001' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicNetworkAccess = 'Enabled' +param roleAssignments = [ + { + name: '6bfff821-2b18-4790-89fa-2849d86bc6be' + 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. @@ -438,7 +599,7 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -467,6 +628,27 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/healthcare-apis/workspace:' + +// Required parameters +param name = 'hawwaf001' +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/hybrid-compute/machine/README.md b/avm/res/hybrid-compute/machine/README.md index b7f4fd21ba..2ad193517d 100644 --- a/avm/res/hybrid-compute/machine/README.md +++ b/avm/res/hybrid-compute/machine/README.md @@ -59,7 +59,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'HCI' +param name = 'arcmachcimin' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Creates an Arc Machine with maximum configurations_ This instance deploys the module with most of its features enabled. @@ -143,7 +160,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -212,6 +229,55 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'HCI' +param name = 'arcmachcimx' +// Non-required parameters +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 osType = 'Windows' +param patchAssessmentMode = 'AutomaticByPlatform' +param patchMode = 'AutomaticByPlatform' +param privateLinkScopeResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 3: _Creates an VMWare machine using only the defaults_ This instance deploys the module with the minimum set of required parameters. @@ -239,7 +305,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -264,6 +330,23 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'VMware' +param name = 'arcmacvmwmin' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -296,7 +379,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +411,28 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'HCI' +param name = 'arcmacwaf' +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/insights/action-group/README.md b/avm/res/insights/action-group/README.md index becc4cda4d..6d443eba38 100644 --- a/avm/res/insights/action-group/README.md +++ b/avm/res/insights/action-group/README.md @@ -56,7 +56,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -81,6 +81,23 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

+

+ +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. @@ -151,7 +168,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +244,66 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

+

+ +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. @@ -259,7 +336,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -291,6 +368,28 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

+

+ +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** diff --git a/avm/res/insights/activity-log-alert/README.md b/avm/res/insights/activity-log-alert/README.md index 3dc67e6cf2..8a307f678d 100644 --- a/avm/res/insights/activity-log-alert/README.md +++ b/avm/res/insights/activity-log-alert/README.md @@ -85,7 +85,7 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

-via JSON Parameter file +via JSON parameters file ```json { @@ -139,6 +139,52 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

+

+ +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. @@ -229,7 +275,7 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

-via JSON Parameter file +via JSON parameters file ```json { @@ -325,6 +371,86 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

+

+ +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. @@ -396,7 +522,7 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

-via JSON Parameter file +via JSON parameters file ```json { @@ -471,6 +597,67 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

+

+ +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** diff --git a/avm/res/insights/component/README.md b/avm/res/insights/component/README.md index e4f7b78ac5..5d3c5bd464 100644 --- a/avm/res/insights/component/README.md +++ b/avm/res/insights/component/README.md @@ -58,7 +58,7 @@ module component 'br/public:avm/res/insights/component:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,23 @@ module component 'br/public:avm/res/insights/component:' = {

+

+ +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. @@ -152,7 +169,7 @@ module component 'br/public:avm/res/insights/component:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -233,6 +250,65 @@ module component 'br/public:avm/res/insights/component:' = {

+

+ +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 forceCustomerStorageForProfiler = true +param linkedStorageAccountResourceId = '' +param location = '' +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. @@ -279,7 +355,7 @@ module component 'br/public:avm/res/insights/component:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -327,6 +403,42 @@ module component 'br/public:avm/res/insights/component:' = {

+

+ +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** diff --git a/avm/res/insights/data-collection-endpoint/README.md b/avm/res/insights/data-collection-endpoint/README.md index a2f09497c1..f84c7e1926 100644 --- a/avm/res/insights/data-collection-endpoint/README.md +++ b/avm/res/insights/data-collection-endpoint/README.md @@ -56,7 +56,7 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

+

+ +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. @@ -135,7 +151,7 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

-via JSON Parameter file +via JSON parameters file ```json { @@ -200,6 +216,53 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

+

+ +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. @@ -233,7 +296,7 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

-via JSON Parameter file +via JSON parameters file ```json { @@ -268,6 +331,29 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

+

+ +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** diff --git a/avm/res/insights/data-collection-rule/README.md b/avm/res/insights/data-collection-rule/README.md index 300de97955..cc7b091211 100644 --- a/avm/res/insights/data-collection-rule/README.md +++ b/avm/res/insights/data-collection-rule/README.md @@ -74,7 +74,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -110,6 +110,34 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -219,7 +247,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -330,6 +358,105 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -420,7 +547,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -510,6 +637,86 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -579,7 +786,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -648,6 +855,65 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -715,7 +981,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -780,6 +1046,63 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -962,7 +1285,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1144,6 +1467,178 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -1263,7 +1758,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1388,6 +1883,115 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -1524,7 +2128,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1660,6 +2264,132 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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. @@ -1796,7 +2526,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1932,6 +2662,132 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

+

+ +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** diff --git a/avm/res/insights/diagnostic-setting/README.md b/avm/res/insights/diagnostic-setting/README.md index 21e1fae6f8..17ab873d61 100644 --- a/avm/res/insights/diagnostic-setting/README.md +++ b/avm/res/insights/diagnostic-setting/README.md @@ -53,7 +53,7 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting: -

via JSON Parameter file +via JSON parameters file ```json { @@ -76,6 +76,21 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:

+

+ +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. @@ -109,7 +124,7 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting: -

via JSON Parameter file +via JSON parameters file ```json { @@ -148,6 +163,29 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:

+

+ +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. @@ -181,7 +219,7 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting: -

via JSON Parameter file +via JSON parameters file ```json { @@ -220,6 +258,29 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:

+

+ +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** diff --git a/avm/res/insights/metric-alert/README.md b/avm/res/insights/metric-alert/README.md index 121b127c85..6f390fc6c6 100644 --- a/avm/res/insights/metric-alert/README.md +++ b/avm/res/insights/metric-alert/README.md @@ -72,7 +72,7 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -115,6 +115,39 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

+

+ +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. @@ -185,7 +218,7 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -265,6 +298,66 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

+

+ +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. @@ -311,7 +404,7 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -365,6 +458,42 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

+

+ +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** diff --git a/avm/res/insights/private-link-scope/README.md b/avm/res/insights/private-link-scope/README.md index e8ef974f3c..82c8c5da93 100644 --- a/avm/res/insights/private-link-scope/README.md +++ b/avm/res/insights/private-link-scope/README.md @@ -60,7 +60,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

-via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

+

+ +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. @@ -269,7 +285,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

-via JSON Parameter file +via JSON parameters file ```json { @@ -464,6 +480,183 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

+

+ +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. @@ -610,7 +803,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

-via JSON Parameter file +via JSON parameters file ```json { @@ -758,6 +951,142 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

+

+ +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** diff --git a/avm/res/insights/scheduled-query-rule/README.md b/avm/res/insights/scheduled-query-rule/README.md index 7497372fa6..617dc4cecc 100644 --- a/avm/res/insights/scheduled-query-rule/README.md +++ b/avm/res/insights/scheduled-query-rule/README.md @@ -87,7 +87,7 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -149,6 +149,54 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:

+

+ +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. @@ -240,7 +288,7 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -351,6 +399,87 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:

+

+ +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. @@ -418,7 +547,7 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule: -

via JSON Parameter file +via JSON parameters file ```json { @@ -499,6 +628,63 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:

+

+ +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** diff --git a/avm/res/insights/webtest/README.md b/avm/res/insights/webtest/README.md index ef3bac6253..f9f5197cd4 100644 --- a/avm/res/insights/webtest/README.md +++ b/avm/res/insights/webtest/README.md @@ -62,7 +62,7 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -96,6 +96,28 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

+

+ +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. @@ -162,7 +184,7 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -240,6 +262,62 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

+

+ +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. @@ -281,7 +359,7 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -330,6 +408,37 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

+

+ +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** diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 9997df4ed0..880c933a5f 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -66,7 +66,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -91,6 +91,23 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

+

+ +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 +param location = '' +``` + +
+

+ ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -152,7 +169,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -213,6 +230,57 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

+

+ +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' + } + } + ] + } + } +] +param location = '' +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -466,7 +534,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -737,6 +805,249 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

+

+ +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 = [ + { + attributesExp: 1725109032 + attributesNbf: 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: '' + } + ] + } + 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 = [ + { + attributesExp: 1702648632 + attributesNbf: 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. @@ -798,7 +1109,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -859,6 +1170,57 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

+

+ +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' + } + } + ] + } + } +] +param location = '' +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -968,7 +1330,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1091,6 +1453,105 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

+

+ +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 location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +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** diff --git a/avm/res/kubernetes-configuration/extension/README.md b/avm/res/kubernetes-configuration/extension/README.md index 8c9870da2e..2467e5fb16 100644 --- a/avm/res/kubernetes-configuration/extension/README.md +++ b/avm/res/kubernetes-configuration/extension/README.md @@ -61,7 +61,7 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

-via JSON Parameter file +via JSON parameters file ```json { @@ -95,6 +95,26 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/extension:' + +// Required parameters +param clusterName = '' +param extensionType = 'microsoft.flux' +param name = 'kcemin001' +// Non-required parameters +param location = '' +param releaseNamespace = 'flux-system' +param releaseTrain = 'Stable' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -154,7 +174,7 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

-via JSON Parameter file +via JSON parameters file ```json { @@ -223,6 +243,55 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/extension:' + +// Required parameters +param clusterName = '' +param extensionType = 'microsoft.flux' +param name = 'kcemax001' +// Non-required parameters +param configurationSettings = { + 'image-automation-controller.enabled': 'false' + 'image-reflector-controller.enabled': 'false' + 'kustomize-controller.enabled': 'true' + 'notification-controller.enabled': 'false' + 'source-controller.enabled': 'true' +} +param fluxConfigurations = [ + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' + } + kustomizations: { + unified: { + path: './cluster-manifests' + } + } + namespace: 'flux-system' + scope: 'cluster' + suspend: false + } +] +param location = '' +param releaseNamespace = 'flux-system' +param releaseTrain = 'Stable' +param version = '0.5.2' +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -282,7 +351,7 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

-via JSON Parameter file +via JSON parameters file ```json { @@ -351,6 +420,55 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/extension:' + +// Required parameters +param clusterName = '' +param extensionType = 'microsoft.flux' +param name = 'kcewaf001' +// Non-required parameters +param configurationSettings = { + 'image-automation-controller.enabled': 'false' + 'image-reflector-controller.enabled': 'false' + 'kustomize-controller.enabled': 'true' + 'notification-controller.enabled': 'false' + 'source-controller.enabled': 'true' +} +param fluxConfigurations = [ + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' + } + kustomizations: { + unified: { + path: './cluster-manifests' + } + } + namespace: 'flux-system' + scope: 'cluster' + suspend: false + } +] +param location = '' +param releaseNamespace = 'flux-system' +param releaseTrain = 'Stable' +param version = '0.5.2' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/kubernetes-configuration/flux-configuration/README.md b/avm/res/kubernetes-configuration/flux-configuration/README.md index be9ed2ecb7..57c4931d74 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/README.md +++ b/avm/res/kubernetes-configuration/flux-configuration/README.md @@ -73,7 +73,7 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

-via JSON Parameter file +via JSON parameters file ```json { @@ -125,6 +125,40 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/flux-configuration:' + +// Required parameters +param clusterName = '' +param kustomizations = { + unified: { + path: './cluster-manifests' + } +} +param name = 'kcfcmin001' +param namespace = 'flux-system' +param scope = 'cluster' +param sourceKind = 'GitRepository' +// Non-required parameters +param gitRepository = { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' +} +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -180,7 +214,7 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

-via JSON Parameter file +via JSON parameters file ```json { @@ -243,6 +277,51 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/flux-configuration:' + +// Required parameters +param clusterName = '' +param kustomizations = { + unified: { + dependsOn: [] + force: false + path: './cluster-manifests' + postBuild: { + substitute: { + TEST_VAR1: 'foo' + TEST_VAR2: 'bar' + } + } + prune: true + syncIntervalInSeconds: 300 + timeoutInSeconds: 300 + } +} +param name = 'kcfcmax001' +param namespace = 'flux-system' +param scope = 'cluster' +param sourceKind = 'GitRepository' +// Non-required parameters +param gitRepository = { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' +} +param location = '' +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -292,7 +371,7 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

-via JSON Parameter file +via JSON parameters file ```json { @@ -349,6 +428,45 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/flux-configuration:' + +// Required parameters +param clusterName = '' +param kustomizations = { + unified: { + dependsOn: [] + force: false + path: './cluster-manifests' + prune: true + syncIntervalInSeconds: 300 + timeoutInSeconds: 300 + } +} +param name = 'kcfcwaf001' +param namespace = 'flux-system' +param scope = 'cluster' +param sourceKind = 'GitRepository' +// Non-required parameters +param gitRepository = { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' +} +param location = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/kusto/cluster/README.md b/avm/res/kusto/cluster/README.md index 40d7a0e115..6c6e0b22ed 100644 --- a/avm/res/kusto/cluster/README.md +++ b/avm/res/kusto/cluster/README.md @@ -63,7 +63,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,23 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcmin0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -175,7 +192,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -302,6 +319,83 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcmax0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param acceptedAudiences = [ + { + value: 'https://contoso.com' + } +] +param allowedFqdnList = [ + 'contoso.com' +] +param allowedIpRangeList = [ + '192.168.1.1' +] +param autoScaleMax = 6 +param autoScaleMin = 3 +param capacity = 3 +param enableAutoScale = true +param enableAutoStop = true +param enableDiskEncryption = true +param enableDoubleEncryption = true +param enablePublicNetworkAccess = true +param enablePurge = true +param enableRestrictOutboundNetworkAccess = true +param enableStreamingIngest = true +param enableZoneRedundant = true +param engineType = 'V3' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param principalAssignments = [ + { + principalId: '' + principalType: 'Group' + role: 'AllDatabasesViewer' + } +] +param publicIPType = 'DualStack' +param roleAssignments = [ + { + name: 'c2a4b728-c3d0-47f5-afbb-ea45c45859de' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
+

+ ### Example 3: _Private endpoint-enabled deployment_ This instance deploys the module with private endpoints. @@ -360,7 +454,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -424,6 +518,54 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcpe0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param enablePublicNetworkAccess = false +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'cluster' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'cluster' + subnetResourceId: '' + } +] +param publicIPType = 'IPv4' +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. @@ -474,7 +616,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -548,6 +690,46 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcwaf0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param autoScaleMax = 10 +param autoScaleMin = 3 +param capacity = 3 +param enableAutoScale = true +param enableAutoStop = true +param enableDiskEncryption = true +param enableDoubleEncryption = true +param enablePublicNetworkAccess = false +param enableZoneRedundant = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param tier = 'Standard' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/load-test-service/load-test/README.md b/avm/res/load-test-service/load-test/README.md index 687a4e16a1..f2d587f3a7 100644 --- a/avm/res/load-test-service/load-test/README.md +++ b/avm/res/load-test-service/load-test/README.md @@ -57,7 +57,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/load-test-service/load-test:' + +// Required parameters +param name = 'ltmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -136,7 +152,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -199,6 +215,53 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/load-test-service/load-test:' + +// Required parameters +param name = 'ltmax001' +// Non-required parameters +param loadTestDescription = 'This is a test load test to validate the module.' +param location = '' +param lock = { + kind: 'None' +} +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + name: 'd37a15bc-8634-4f4f-a736-700c1b955cd7' + 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 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. @@ -235,7 +298,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -271,6 +334,32 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

+

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

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -304,7 +393,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -339,6 +428,29 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/load-test-service/load-test:' + +// Required parameters +param name = 'ltwaf001' +// Non-required parameters +param enableTelemetry = '' +param loadTestDescription = 'This is a sample load test.' +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/logic/workflow/README.md b/avm/res/logic/workflow/README.md index a3e33ad480..9de770ef08 100644 --- a/avm/res/logic/workflow/README.md +++ b/avm/res/logic/workflow/README.md @@ -58,7 +58,7 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -184,7 +200,7 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -298,6 +314,100 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/logic/workflow:' + +// Required parameters +param name = 'lwmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '1f98c16b-ea00-4686-8b81-05353b594ea3' + 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 workflowActions = { + HTTP: { + inputs: { + body: { + BeginPeakTime: '' + EndPeakTime: '' + HostPoolName: '' + LAWorkspaceName: '' + LimitSecondsToForceLogOffUser: '' + LogOffMessageBody: '' + LogOffMessageTitle: '' + MinimumNumberOfRDSH: 1 + ResourceGroupName: '' + SessionThresholdPerCPU: 1 + UtcOffset: '' + } + method: 'POST' + uri: 'https://testStringForValidation.com' + } + type: 'Http' + } +} +param workflowTriggers = { + Recurrence: { + recurrence: { + frequency: 'Minute' + interval: 15 + } + type: 'Recurrence' + } +} +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -383,7 +493,7 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -476,6 +586,81 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/logic/workflow:' + +// Required parameters +param name = 'lwwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param workflowActions = { + HTTP: { + inputs: { + body: { + BeginPeakTime: '' + EndPeakTime: '' + HostPoolName: '' + LAWorkspaceName: '' + LimitSecondsToForceLogOffUser: '' + LogOffMessageBody: '' + LogOffMessageTitle: '' + MinimumNumberOfRDSH: 1 + ResourceGroupName: '' + SessionThresholdPerCPU: 1 + UtcOffset: '' + } + method: 'POST' + uri: 'https://testStringForValidation.com' + } + type: 'Http' + } +} +param workflowTriggers = { + Recurrence: { + recurrence: { + frequency: 'Minute' + interval: 15 + } + type: 'Recurrence' + } +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/machine-learning-services/workspace/README.md b/avm/res/machine-learning-services/workspace/README.md index e8b2aa23b5..5257a24585 100644 --- a/avm/res/machine-learning-services/workspace/README.md +++ b/avm/res/machine-learning-services/workspace/README.md @@ -95,7 +95,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

via JSON Parameter file +via JSON parameters file ```json { @@ -160,6 +160,51 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswai001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param connections = [ + { + category: 'AIServices' + connectionProperties: { + authType: 'ApiKey' + credentials: { + key: 'key' + } + } + metadata: { + ApiType: 'Azure' + ApiVersion: '2023-07-01-preview' + DeploymentApiVersion: '2023-10-01-preview' + Location: '' + ResourceId: '' + } + name: 'ai' + target: '' + } +] +param kind = 'Hub' +param location = '' +param workspaceHubConfig = { + additionalWorkspaceStorageAccounts: '' + defaultWorkspaceResourceGroup: '' +} +``` + +
+

+ ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -190,7 +235,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +269,26 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswmin001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param location = '' +``` + +
+

+ ### Example 3: _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. @@ -279,7 +344,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

via JSON Parameter file +via JSON parameters file ```json { @@ -346,6 +411,51 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswecr001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param managedNetworkSettings = { + isolationMode: 'AllowInternetOutbound' + outboundRules: { + rule: { + category: 'UserDefined' + destination: { + serviceResourceId: '' + subresourceTarget: 'blob' + } + type: 'PrivateEndpoint' + } + } +} +param primaryUserAssignedIdentity = '' +``` + +
+

+ ### Example 4: _Creating Azure ML managed feature store_ This instance deploys an Azure ML managed feature store. @@ -382,7 +492,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

via JSON Parameter file +via JSON parameters file ```json { @@ -426,6 +536,32 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswfs001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param featureStoreSettings = { + computeRuntime: { + sparkRuntimeVersion: '3.3' + } +} +param kind = 'FeatureStore' +param location = '' +``` + +
+

+ ### Example 5: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -591,7 +727,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

via JSON Parameter file +via JSON parameters file ```json { @@ -792,6 +928,161 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswmax001' +param sku = 'Premium' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param computes = [ + { + computeLocation: '' + computeType: 'AmlCompute' + description: 'Default CPU Cluster' + disableLocalAuth: false + location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + name: 'DefaultCPU' + properties: { + enableNodePublicIp: true + isolatedNetwork: false + osType: 'Linux' + remoteLoginPortPublicAccess: 'Disabled' + scaleSettings: { + maxNodeCount: 3 + minNodeCount: 0 + nodeIdleTimeBeforeScaleDown: 'PT5M' + } + vmPriority: 'Dedicated' + vmSize: 'STANDARD_DS11_V2' + } + sku: 'Basic' + } +] +param connections = [ + { + category: 'ApiKey' + connectionProperties: { + authType: 'ApiKey' + credentials: { + key: 'key' + } + } + name: 'connection' + target: 'https://example.com' + } +] +param description = 'The cake is a lie.' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param discoveryUrl = 'http://example.com' +param imageBuildCompute = 'testcompute' +param kind = 'Default' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param managedNetworkSettings = { + isolationMode: 'Disabled' +} +param primaryUserAssignedIdentity = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + name: 'group1' + privateDnsZoneGroupConfigs: [ + { + name: 'config1' + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + name: 'group2' + privateDnsZoneGroupConfigs: [ + { + name: 'config2' + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'f9b5b0d9-f27e-4c89-bacf-1bbc4a99dbce' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param serverlessComputeSettings = { + serverlessComputeCustomSubnet: '' + serverlessComputeNoPublicIP: true +} +param systemDatastoresAuthMode = 'accessKey' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -881,7 +1172,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

via JSON Parameter file +via JSON parameters file ```json { @@ -984,6 +1275,85 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswwaf001' +param sku = 'Standard' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param managedNetworkSettings = { + isolationMode: 'AllowOnlyApprovedOutbound' + outboundRules: { + rule1: { + category: 'UserDefined' + destination: { + serviceResourceId: '' + sparkEnabled: true + subresourceTarget: 'blob' + } + type: 'PrivateEndpoint' + } + rule2: { + category: 'UserDefined' + destination: 'pypi.org' + type: 'FQDN' + } + rule3: { + category: 'UserDefined' + destination: { + portRanges: '80,443' + protocol: 'TCP' + serviceTag: 'AppService' + } + type: 'ServiceTag' + } + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param systemDatastoresAuthMode = 'identity' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/maintenance/maintenance-configuration/README.md b/avm/res/maintenance/maintenance-configuration/README.md index d8187c2a1f..a7e122c5da 100644 --- a/avm/res/maintenance/maintenance-configuration/README.md +++ b/avm/res/maintenance/maintenance-configuration/README.md @@ -56,7 +56,7 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -161,7 +177,7 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

-via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +274,79 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/maintenance/maintenance-configuration:' + +// Required parameters +param name = 'mmcmax001' +// Non-required parameters +param extensionProperties = { + InGuestPatchMode: 'User' +} +param installPatches = { + linuxParameters: { + classificationsToInclude: '' + packageNameMasksToExclude: '' + packageNameMasksToInclude: '' + } + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + kbNumbersToExclude: '' + kbNumbersToInclude: '' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maintenanceScope = 'InGuestPatch' +param maintenanceWindow = { + duration: '03:00' + expirationDateTime: '9999-12-31 23:59:59' + recurEvery: 'Day' + startDateTime: '2022-12-31 13:00' + timeZone: 'W. Europe Standard Time' +} +param namespace = 'mmcmaxns' +param roleAssignments = [ + { + name: 'd78ec5f7-4692-4f43-8c17-7569466bbed5' + 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 = 'Custom' +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -318,7 +407,7 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

-via JSON Parameter file +via JSON parameters file ```json { @@ -388,6 +477,56 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/maintenance/maintenance-configuration:' + +// Required parameters +param name = 'mmcwaf001' +// Non-required parameters +param extensionProperties = { + InGuestPatchMode: 'User' +} +param installPatches = { + linuxParameters: { + classificationsToInclude: '' + packageNameMasksToExclude: '' + packageNameMasksToInclude: '' + } + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + kbNumbersToExclude: '' + kbNumbersToInclude: '' + } +} +param location = '' +param maintenanceScope = 'InGuestPatch' +param maintenanceWindow = { + duration: '03:00' + expirationDateTime: '9999-12-31 23:59:59' + recurEvery: 'Day' + startDateTime: '2022-12-31 13:00' + timeZone: 'W. Europe Standard Time' +} +param namespace = 'mmcwafns' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param visibility = 'Custom' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/managed-identity/user-assigned-identity/README.md b/avm/res/managed-identity/user-assigned-identity/README.md index 43908d19fe..c84308a3fc 100644 --- a/avm/res/managed-identity/user-assigned-identity/README.md +++ b/avm/res/managed-identity/user-assigned-identity/README.md @@ -57,7 +57,7 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

-via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

+

+ +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. @@ -151,7 +167,7 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

-via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +243,68 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

+

+ +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. @@ -280,7 +358,7 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

-via JSON Parameter file +via JSON parameters file ```json { @@ -335,6 +413,49 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

+

+ +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** diff --git a/avm/res/managed-services/registration-definition/README.md b/avm/res/managed-services/registration-definition/README.md index 85cea5188b..98aa0aafa7 100644 --- a/avm/res/managed-services/registration-definition/README.md +++ b/avm/res/managed-services/registration-definition/README.md @@ -75,7 +75,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

-via JSON Parameter file +via JSON parameters file ```json { @@ -115,6 +115,34 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdmin Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -163,7 +191,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

-via JSON Parameter file +via JSON parameters file ```json { @@ -215,6 +243,44 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + principalIdDisplayName: 'Lighthouse Contributor' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + principalIdDisplayName: 'Managed Services Registration assignment Delete Role' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } + { + delegatedRoleDefinitionIds: [ + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ] + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdmax Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +param registrationId = '' +``` + +
+

+ ### Example 3: _Resource group deployment_ This instance deploys the module on a resource group. @@ -255,7 +321,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

-via JSON Parameter file +via JSON parameters file ```json { @@ -301,6 +367,36 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdrg Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +param registrationId = '' +param resourceGroupName = '' +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -340,7 +436,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

-via JSON Parameter file +via JSON parameters file ```json { @@ -383,6 +479,35 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdwaf Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +param resourceGroupName = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/management/management-group/README.md b/avm/res/management/management-group/README.md index 774c011294..ebd306ab99 100644 --- a/avm/res/management/management-group/README.md +++ b/avm/res/management/management-group/README.md @@ -59,7 +59,7 @@ module managementGroup 'br/public:avm/res/management/management-group:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -81,6 +81,22 @@ module managementGroup 'br/public:avm/res/management/management-group:'

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -109,7 +125,7 @@ module managementGroup 'br/public:avm/res/management/management-group:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -137,6 +153,24 @@ module managementGroup 'br/public:avm/res/management/management-group:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/management/management-group:' + +// Required parameters +param name = 'mmgmax001' +// Non-required parameters +param displayName = 'Test MG' +param location = '' +param parentId = '' +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -165,7 +199,7 @@ module managementGroup 'br/public:avm/res/management/management-group:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -193,6 +227,24 @@ module managementGroup 'br/public:avm/res/management/management-group:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/management/management-group:' + +// Required parameters +param name = 'mmgwaf001' +// Non-required parameters +param displayName = 'Test MG' +param location = '' +param parentId = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/net-app/net-app-account/README.md b/avm/res/net-app/net-app-account/README.md index 13b76bd308..3a41e6dc96 100644 --- a/avm/res/net-app/net-app-account/README.md +++ b/avm/res/net-app/net-app-account/README.md @@ -63,7 +63,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -85,6 +85,22 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

+

+ +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. @@ -226,7 +242,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -371,6 +387,137 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

+

+ +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 capacityPools = [ + { + name: 'nanaamax-cp-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + encryptionKeySource: '' + exportPolicyRules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + name: 'nanaamax-vol-001' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + '1' + ] + } + { + encryptionKeySource: '' + exportPolicyRules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + name: 'nanaamax-vol-002' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + '1' + ] + } + ] + } + { + name: 'nanaamax-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 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. @@ -499,7 +646,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -631,6 +778,124 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

+

+ +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: '' + exportPolicyRules: [ + { + allowedClients: '0.0.0.0/0' + 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. @@ -660,7 +925,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -687,6 +952,25 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

+

+ +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** diff --git a/avm/res/network/application-gateway-web-application-firewall-policy/README.md b/avm/res/network/application-gateway-web-application-firewall-policy/README.md index 19c7a54ed5..d66c625612 100644 --- a/avm/res/network/application-gateway-web-application-firewall-policy/README.md +++ b/avm/res/network/application-gateway-web-application-firewall-policy/README.md @@ -62,7 +62,7 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

-via JSON Parameter file +via JSON parameters file ```json { @@ -94,6 +94,30 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

+

+ +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. @@ -144,7 +168,7 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

-via JSON Parameter file +via JSON parameters file ```json { @@ -196,6 +220,46 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

+

+ +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 = { + fileUploadLimitInMb: 10 + 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. @@ -245,7 +309,7 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

-via JSON Parameter file +via JSON parameters file ```json { @@ -296,6 +360,45 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

+

+ +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 + mode: 'Prevention' + state: 'Enabled' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/network/application-gateway/README.md b/avm/res/network/application-gateway/README.md index ad061f01d1..fb363e99f3 100644 --- a/avm/res/network/application-gateway/README.md +++ b/avm/res/network/application-gateway/README.md @@ -136,7 +136,7 @@ module applicationGateway 'br/public:avm/res/network/application-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -248,6 +248,98 @@ module applicationGateway 'br/public:avm/res/network/application-gateway:

+

+ +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. @@ -718,7 +810,7 @@ module applicationGateway 'br/public:avm/res/network/application-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -1230,6 +1322,466 @@ module applicationGateway 'br/public:avm/res/network/application-gateway:

+

+ +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. @@ -1650,7 +2202,7 @@ module applicationGateway 'br/public:avm/res/network/application-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -2108,6 +2660,416 @@ module applicationGateway 'br/public:avm/res/network/application-gateway:

+

+ +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** diff --git a/avm/res/network/application-security-group/README.md b/avm/res/network/application-security-group/README.md index 6ef90cc95a..7ef8c039c8 100644 --- a/avm/res/network/application-security-group/README.md +++ b/avm/res/network/application-security-group/README.md @@ -56,7 +56,7 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

+

+ +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. @@ -132,7 +148,7 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

-via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +204,50 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

+

+ +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. @@ -223,7 +283,7 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

-via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +318,31 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

+

+ +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** diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index ce6a6114ef..5d8d346c88 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -83,7 +83,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -131,6 +131,40 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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. @@ -161,7 +195,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -195,6 +229,26 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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. @@ -250,7 +304,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -305,6 +359,51 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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. @@ -332,7 +431,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -357,6 +456,23 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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. @@ -390,7 +506,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -425,6 +541,29 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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. @@ -457,7 +596,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -489,6 +628,28 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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. @@ -661,7 +822,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -847,6 +1008,168 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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. @@ -890,7 +1213,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -939,6 +1262,39 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1072,7 +1428,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1215,6 +1571,129 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

+

+ +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** diff --git a/avm/res/network/bastion-host/README.md b/avm/res/network/bastion-host/README.md index fc93544fc5..8c95b14dac 100644 --- a/avm/res/network/bastion-host/README.md +++ b/avm/res/network/bastion-host/README.md @@ -99,7 +99,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -164,6 +164,61 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

+

+ +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. @@ -191,7 +246,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -216,6 +271,23 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

+

+ +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 large parameter set_ This instance deploys the module with most of its features enabled. @@ -287,7 +359,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -378,6 +450,67 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

+

+ +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' +} +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -426,7 +559,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -490,6 +623,44 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

+

+ +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** diff --git a/avm/res/network/connection/README.md b/avm/res/network/connection/README.md index 1daee9d401..5bf3869260 100644 --- a/avm/res/network/connection/README.md +++ b/avm/res/network/connection/README.md @@ -64,7 +64,7 @@ module connection 'br/public:avm/res/network/connection:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -102,6 +102,30 @@ module connection 'br/public:avm/res/network/connection:' = {

+

+ +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. @@ -148,7 +172,7 @@ module connection 'br/public:avm/res/network/connection:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -208,6 +232,42 @@ module connection 'br/public:avm/res/network/connection:' = {

+

+ +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. @@ -251,7 +311,7 @@ module connection 'br/public:avm/res/network/connection:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -302,6 +362,39 @@ module connection 'br/public:avm/res/network/connection:' = {

+

+ +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** diff --git a/avm/res/network/ddos-protection-plan/README.md b/avm/res/network/ddos-protection-plan/README.md index 6bdd5c6b3c..6465acbe17 100644 --- a/avm/res/network/ddos-protection-plan/README.md +++ b/avm/res/network/ddos-protection-plan/README.md @@ -56,7 +56,7 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan: -

via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:

+

+ +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. @@ -132,7 +148,7 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan: -

via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +204,50 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:

+

+ +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. @@ -223,7 +283,7 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan: -

via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +318,31 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:

+

+ +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** diff --git a/avm/res/network/dns-forwarding-ruleset/README.md b/avm/res/network/dns-forwarding-ruleset/README.md index e0d4cf14ae..d04be125ef 100644 --- a/avm/res/network/dns-forwarding-ruleset/README.md +++ b/avm/res/network/dns-forwarding-ruleset/README.md @@ -61,7 +61,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset: -

via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,25 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:

+

+ +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. @@ -164,7 +183,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset: -

via JSON Parameter file +via JSON parameters file ```json { @@ -248,6 +267,72 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:

+

+ +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. @@ -286,7 +371,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset: -

via JSON Parameter file +via JSON parameters file ```json { @@ -326,6 +411,34 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:

+

+ +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** diff --git a/avm/res/network/dns-resolver/README.md b/avm/res/network/dns-resolver/README.md index 4642dd8e31..83f5b9b167 100644 --- a/avm/res/network/dns-resolver/README.md +++ b/avm/res/network/dns-resolver/README.md @@ -59,7 +59,7 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

+

+ +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. @@ -151,7 +168,7 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -226,6 +243,63 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

+

+ +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. @@ -274,7 +348,7 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +402,44 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

+

+ +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** diff --git a/avm/res/network/dns-zone/README.md b/avm/res/network/dns-zone/README.md index e7a9c463a3..2d49c7a920 100644 --- a/avm/res/network/dns-zone/README.md +++ b/avm/res/network/dns-zone/README.md @@ -66,7 +66,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,22 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

+

+ +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. @@ -419,7 +435,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -772,6 +788,327 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

+

+ +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. @@ -807,7 +1144,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -842,6 +1179,31 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

+

+ +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** diff --git a/avm/res/network/express-route-circuit/README.md b/avm/res/network/express-route-circuit/README.md index 50e00e3bd5..9f1ad4093b 100644 --- a/avm/res/network/express-route-circuit/README.md +++ b/avm/res/network/express-route-circuit/README.md @@ -60,7 +60,7 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit: -

via JSON Parameter file +via JSON parameters file ```json { @@ -91,6 +91,25 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:

+

+ +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. @@ -165,7 +184,7 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit: -

via JSON Parameter file +via JSON parameters file ```json { @@ -255,6 +274,70 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:

+

+ +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. @@ -310,7 +393,7 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit: -

via JSON Parameter file +via JSON parameters file ```json { @@ -379,6 +462,51 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:

+

+ +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** diff --git a/avm/res/network/express-route-gateway/README.md b/avm/res/network/express-route-gateway/README.md index d66a1ef172..27da9983b7 100644 --- a/avm/res/network/express-route-gateway/README.md +++ b/avm/res/network/express-route-gateway/README.md @@ -57,7 +57,7 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,23 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:

+

+ +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. @@ -138,7 +155,7 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -202,6 +219,52 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:

+

+ +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. @@ -239,7 +302,7 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -282,6 +345,33 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:

+

+ +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** diff --git a/avm/res/network/firewall-policy/README.md b/avm/res/network/firewall-policy/README.md index f0db15c291..067f1a3fe5 100644 --- a/avm/res/network/firewall-policy/README.md +++ b/avm/res/network/firewall-policy/README.md @@ -55,7 +55,7 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -77,6 +77,22 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

+

+ +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. @@ -155,7 +171,7 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -243,6 +259,74 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

+

+ +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 managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param mode = 'Alert' +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. @@ -315,7 +399,7 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -393,6 +477,68 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

+

+ +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** diff --git a/avm/res/network/front-door-web-application-firewall-policy/README.md b/avm/res/network/front-door-web-application-firewall-policy/README.md index 6b4b2dd0df..97df30f6ba 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/README.md +++ b/avm/res/network/front-door-web-application-firewall-policy/README.md @@ -56,7 +56,7 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

+

+ +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. @@ -195,7 +211,7 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

-via JSON Parameter file +via JSON parameters file ```json { @@ -322,6 +338,113 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

+

+ +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. @@ -416,7 +539,7 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

-via JSON Parameter file +via JSON parameters file ```json { @@ -516,6 +639,90 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

+

+ +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** diff --git a/avm/res/network/front-door/README.md b/avm/res/network/front-door/README.md index 23561de663..b68647da31 100644 --- a/avm/res/network/front-door/README.md +++ b/avm/res/network/front-door/README.md @@ -136,7 +136,7 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -247,6 +247,101 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

+

+ +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. @@ -408,7 +503,7 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -587,6 +682,157 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

+

+ +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. @@ -714,7 +960,7 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -855,6 +1101,123 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

+

+ +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** diff --git a/avm/res/network/ip-group/README.md b/avm/res/network/ip-group/README.md index 48dcd81c36..d8c0ac67b6 100644 --- a/avm/res/network/ip-group/README.md +++ b/avm/res/network/ip-group/README.md @@ -56,7 +56,7 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

+

+ +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. @@ -136,7 +152,7 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -198,6 +214,54 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

+

+ +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. @@ -233,7 +297,7 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -268,6 +332,31 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

+

+ +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** diff --git a/avm/res/network/load-balancer/README.md b/avm/res/network/load-balancer/README.md index 4b5103926d..51bbc3fbdb 100644 --- a/avm/res/network/load-balancer/README.md +++ b/avm/res/network/load-balancer/README.md @@ -68,7 +68,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -98,6 +98,28 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

+

+ +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. @@ -245,7 +267,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -408,6 +430,143 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

+

+ +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. @@ -511,7 +670,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -626,6 +785,99 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

+

+ +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. @@ -779,7 +1031,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -948,6 +1200,149 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

+

+ +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. @@ -1057,7 +1452,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1178,6 +1573,105 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

+

+ +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** diff --git a/avm/res/network/local-network-gateway/README.md b/avm/res/network/local-network-gateway/README.md index aa324dae8a..eeac57706a 100644 --- a/avm/res/network/local-network-gateway/README.md +++ b/avm/res/network/local-network-gateway/README.md @@ -60,7 +60,7 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -90,6 +90,26 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:

+

+ +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. @@ -150,7 +170,7 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -220,6 +240,56 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:

+

+ +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. @@ -261,7 +331,7 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway: -

via JSON Parameter file +via JSON parameters file ```json { @@ -310,6 +380,37 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:

+

+ +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** diff --git a/avm/res/network/nat-gateway/README.md b/avm/res/network/nat-gateway/README.md index d12c7b26f7..48846ff683 100644 --- a/avm/res/network/nat-gateway/README.md +++ b/avm/res/network/nat-gateway/README.md @@ -63,7 +63,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,23 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

+

+ +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. @@ -116,7 +133,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -144,6 +161,24 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

+

+ +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. @@ -241,7 +276,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -344,6 +379,93 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

+

+ +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. @@ -380,7 +502,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -416,6 +538,32 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

+

+ +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. @@ -477,7 +625,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -542,6 +690,57 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

+

+ +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** diff --git a/avm/res/network/network-interface/README.md b/avm/res/network/network-interface/README.md index 6b6f123af8..a9368e2156 100644 --- a/avm/res/network/network-interface/README.md +++ b/avm/res/network/network-interface/README.md @@ -63,7 +63,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,28 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

+

+ +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. @@ -180,7 +202,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -273,6 +295,83 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

+

+ +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. @@ -337,7 +436,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -403,6 +502,60 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

+

+ +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** diff --git a/avm/res/network/network-manager/README.md b/avm/res/network/network-manager/README.md index ea6a3831c0..cbff3f3f1f 100644 --- a/avm/res/network/network-manager/README.md +++ b/avm/res/network/network-manager/README.md @@ -72,7 +72,7 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -106,6 +106,30 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = 'nnmmin001' +param networkManagerScopeAccesses = [ + 'Connectivity' +] +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. @@ -362,7 +386,7 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -632,6 +656,252 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = '' +param networkManagerScopeAccesses = [ + 'Connectivity' + 'SecurityAdmin' +] +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' + name: 'network-group-spokes-1' + staticMembers: [ + { + name: 'virtualNetworkSpoke1' + resourceId: '' + } + { + name: 'virtualNetworkSpoke2' + resourceId: '' + } + ] + } + { + name: 'network-group-spokes-2' + staticMembers: [ + { + name: 'virtualNetworkSpoke3' + resourceId: '' + } + ] + } + { + name: 'network-group-spokes-3' + } +] +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 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. @@ -671,7 +941,7 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -712,6 +982,35 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = 'nnmwaf001' +param networkManagerScopeAccesses = [ + 'SecurityAdmin' +] +param networkManagerScopes = { + subscriptions: [ + '' + ] +} +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/network/network-security-group/README.md b/avm/res/network/network-security-group/README.md index 3de82ead53..5fa87016be 100644 --- a/avm/res/network/network-security-group/README.md +++ b/avm/res/network/network-security-group/README.md @@ -57,7 +57,7 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group:

+

+ +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. @@ -231,7 +247,7 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -389,6 +405,148 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group:

+

+ +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. @@ -438,7 +596,7 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group: -

via JSON Parameter file +via JSON parameters file ```json { @@ -487,6 +645,45 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group:

+

+ +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** diff --git a/avm/res/network/network-watcher/README.md b/avm/res/network/network-watcher/README.md index d26f9648ba..f35d694880 100644 --- a/avm/res/network/network-watcher/README.md +++ b/avm/res/network/network-watcher/README.md @@ -55,7 +55,7 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -72,6 +72,19 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

+

+ +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. @@ -189,7 +202,7 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -310,6 +323,113 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

+

+ +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. @@ -408,7 +528,7 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -508,6 +628,94 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

+

+ +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** diff --git a/avm/res/network/private-dns-zone/README.md b/avm/res/network/private-dns-zone/README.md index bcc558ab55..bc18b62e9c 100644 --- a/avm/res/network/private-dns-zone/README.md +++ b/avm/res/network/private-dns-zone/README.md @@ -65,7 +65,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,22 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

+

+ +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. @@ -362,7 +378,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -657,6 +673,271 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

+

+ +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. @@ -692,7 +973,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -727,6 +1008,31 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

+

+ +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** diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index c063742796..3db54f7e96 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -70,7 +70,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -108,6 +108,34 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

+

+ +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 location = '' +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. @@ -206,7 +234,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -320,6 +348,94 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

+

+ +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`. @@ -366,7 +482,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -414,6 +530,42 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

+

+ +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 location = '' +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. @@ -482,7 +634,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -562,6 +714,64 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

+

+ +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 location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +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** diff --git a/avm/res/network/private-link-service/README.md b/avm/res/network/private-link-service/README.md index 3df921a3c3..53aea96467 100644 --- a/avm/res/network/private-link-service/README.md +++ b/avm/res/network/private-link-service/README.md @@ -71,7 +71,7 @@ module privateLinkService 'br/public:avm/res/network/private-link-service: -

via JSON Parameter file +via JSON parameters file ```json { @@ -112,6 +112,37 @@ module privateLinkService 'br/public:avm/res/network/private-link-service:

+

+ +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. @@ -198,7 +229,7 @@ module privateLinkService 'br/public:avm/res/network/private-link-service: -

via JSON Parameter file +via JSON parameters file ```json { @@ -298,6 +329,82 @@ module privateLinkService 'br/public:avm/res/network/private-link-service:

+

+ +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. @@ -361,7 +468,7 @@ module privateLinkService 'br/public:avm/res/network/private-link-service: -

via JSON Parameter file +via JSON parameters file ```json { @@ -434,6 +541,59 @@ module privateLinkService 'br/public:avm/res/network/private-link-service:

+

+ +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** diff --git a/avm/res/network/public-ip-address/README.md b/avm/res/network/public-ip-address/README.md index 6c71fc4c87..8ba95ec8ab 100644 --- a/avm/res/network/public-ip-address/README.md +++ b/avm/res/network/public-ip-address/README.md @@ -57,7 +57,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

+

+ +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. @@ -154,7 +170,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -249,6 +265,71 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

+

+ +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 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. @@ -322,7 +403,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -415,6 +496,69 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

+

+ +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** diff --git a/avm/res/network/public-ip-prefix/README.md b/avm/res/network/public-ip-prefix/README.md index 22a3790bf4..a61f1f8244 100644 --- a/avm/res/network/public-ip-prefix/README.md +++ b/avm/res/network/public-ip-prefix/README.md @@ -57,7 +57,7 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,23 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

+

+ +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: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -141,7 +158,7 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -206,6 +223,55 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

+

+ +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 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 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -238,7 +304,7 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -270,6 +336,28 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

+

+ +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** diff --git a/avm/res/network/route-table/README.md b/avm/res/network/route-table/README.md index a0a83836fb..8e00dd425e 100644 --- a/avm/res/network/route-table/README.md +++ b/avm/res/network/route-table/README.md @@ -56,7 +56,7 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

+

+ +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. @@ -142,7 +158,7 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -210,6 +226,60 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

+

+ +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. @@ -255,7 +325,7 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -302,6 +372,41 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

+

+ +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** diff --git a/avm/res/network/service-endpoint-policy/README.md b/avm/res/network/service-endpoint-policy/README.md index 2fb4267d72..7bfd1efdeb 100644 --- a/avm/res/network/service-endpoint-policy/README.md +++ b/avm/res/network/service-endpoint-policy/README.md @@ -56,7 +56,7 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

+

+ +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. @@ -132,7 +148,7 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

-via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +204,50 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

+

+ +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. @@ -219,7 +279,7 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

-via JSON Parameter file +via JSON parameters file ```json { @@ -248,6 +308,27 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

+

+ +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** diff --git a/avm/res/network/trafficmanagerprofile/README.md b/avm/res/network/trafficmanagerprofile/README.md index 11fa33f627..707111d930 100644 --- a/avm/res/network/trafficmanagerprofile/README.md +++ b/avm/res/network/trafficmanagerprofile/README.md @@ -57,7 +57,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile: -

via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:

+

+ +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. @@ -148,7 +164,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile: -

via JSON Parameter file +via JSON parameters file ```json { @@ -223,6 +239,65 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:

+

+ +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. @@ -301,7 +376,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile: -

via JSON Parameter file +via JSON parameters file ```json { @@ -385,6 +460,74 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:

+

+ +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** diff --git a/avm/res/network/virtual-hub/README.md b/avm/res/network/virtual-hub/README.md index ba68607e76..33a3d5861a 100644 --- a/avm/res/network/virtual-hub/README.md +++ b/avm/res/network/virtual-hub/README.md @@ -62,7 +62,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -90,6 +90,24 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

+

+ +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. @@ -153,7 +171,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +242,59 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

+

+ +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. @@ -273,7 +344,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -338,6 +409,45 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

+

+ +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. @@ -401,7 +511,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -472,6 +582,59 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

+

+ +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** diff --git a/avm/res/network/virtual-network-gateway/README.md b/avm/res/network/virtual-network-gateway/README.md index 85c0d4ad2e..290070237e 100644 --- a/avm/res/network/virtual-network-gateway/README.md +++ b/avm/res/network/virtual-network-gateway/README.md @@ -95,7 +95,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -159,6 +159,48 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 = 'nvgavpn001' +param vNetResourceId = '' +// Non-required parameters +param domainNameLabel = [ + 'dm-nvgavpn' +] +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnClientAadConfiguration = { + aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' + aadIssuer: '' + aadTenant: '' + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnClientProtocols: [ + 'OpenVPN' + ] +} +param vpnType = 'RouteBased' +``` + +
+

+ ### Example 2: _VPN Active Active with BGP settings_ This instance deploys the module with the VPN Active Active with BGP settings. @@ -206,7 +248,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -275,6 +317,43 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 3: _VPN Active Active with BGP settings_ This instance deploys the module with the VPN Active Active with APIPA BGP settings. @@ -330,7 +409,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -407,6 +486,51 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 4: _VPN Active Active without BGP settings_ This instance deploys the module with the VPN Active Active without BGP settings. @@ -454,7 +578,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -523,6 +647,43 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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. @@ -575,7 +736,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -649,6 +810,48 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 without BGP settings_ This instance deploys the module with the VPN Active Passive without BGP settings. @@ -696,7 +899,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -765,6 +968,43 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 7: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -802,7 +1042,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -845,6 +1085,33 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 8: _ExpressRoute_ This instance deploys the module with the ExpressRoute set of required parameters. @@ -886,7 +1153,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -937,6 +1204,37 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 gatewayPipName = 'pip-nvger' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'ErGw1AZ' +``` + +
+

+ ### Example 9: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -1069,7 +1367,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1233,6 +1531,128 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + activeGatewayPipName: 'nvgmax001-pip2' + 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 = '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 10: _Using SKU without Availability Zones_ This instance deploys the module with a SKU that does not support Availability Zones. @@ -1266,7 +1686,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1305,6 +1725,29 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 11: _VPN_ This instance deploys the module with the VPN set of required parameters. @@ -1352,7 +1795,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1421,6 +1864,43 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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 12: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1534,7 +2014,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

-via JSON Parameter file +via JSON parameters file ```json { @@ -1677,6 +2157,109 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

+

+ +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** diff --git a/avm/res/network/virtual-network/README.md b/avm/res/network/virtual-network/README.md index b3f52a10bb..c61cf59589 100644 --- a/avm/res/network/virtual-network/README.md +++ b/avm/res/network/virtual-network/README.md @@ -65,7 +65,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,25 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

+

+ +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. @@ -131,7 +150,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -170,6 +189,35 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

+

+ +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. @@ -308,7 +356,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -458,6 +506,134 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

+

+ +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. @@ -520,7 +696,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -586,6 +762,58 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

+

+ +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. @@ -684,7 +912,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -790,6 +1018,94 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

+

+ +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** diff --git a/avm/res/network/virtual-wan/README.md b/avm/res/network/virtual-wan/README.md index 418464fd84..589165c1e2 100644 --- a/avm/res/network/virtual-wan/README.md +++ b/avm/res/network/virtual-wan/README.md @@ -56,7 +56,7 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -136,7 +152,7 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -204,6 +220,54 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

+

+ +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. @@ -239,7 +303,7 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -280,6 +344,31 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

+

+ +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 location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param type = 'Basic' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/network/vpn-gateway/README.md b/avm/res/network/vpn-gateway/README.md index cd27b9108d..26eec74c1c 100644 --- a/avm/res/network/vpn-gateway/README.md +++ b/avm/res/network/vpn-gateway/README.md @@ -59,7 +59,7 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-gateway:' + +// Required parameters +param name = 'vpngmin001' +param virtualHubResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -155,7 +172,7 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -234,6 +251,67 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

+

+ +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. @@ -305,7 +383,7 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -384,6 +462,67 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

+

+ +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 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' + } +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/network/vpn-site/README.md b/avm/res/network/vpn-site/README.md index 63156245bb..92f162d8a7 100644 --- a/avm/res/network/vpn-site/README.md +++ b/avm/res/network/vpn-site/README.md @@ -62,7 +62,7 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -95,6 +95,27 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

+

+ +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' +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -190,7 +211,7 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -295,6 +316,91 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

+

+ +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. @@ -371,7 +477,7 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -455,6 +561,72 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

+

+ +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 = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +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** diff --git a/avm/res/operational-insights/workspace/README.md b/avm/res/operational-insights/workspace/README.md index 59a1b53a9a..40a8d48755 100644 --- a/avm/res/operational-insights/workspace/README.md +++ b/avm/res/operational-insights/workspace/README.md @@ -344,7 +344,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -673,6 +673,299 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

+

+ +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 gallerySolutions = [ + { + name: 'AzureAutomation' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + resourceId: '' + } +] +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' +} +param useResourcePermissions = true +``` + +
+

+ ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -699,7 +992,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -721,6 +1014,22 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

+

+ +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. @@ -1020,7 +1329,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -1347,6 +1656,295 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

+

+ +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 gallerySolutions = [ + { + name: 'AzureAutomation' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + resourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: 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' +} +param useResourcePermissions = true +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1513,7 +2111,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -1699,6 +2297,162 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

+

+ +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 gallerySolutions = [ + { + name: 'AzureAutomation' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + resourceId: '' + } +] +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' +} +param useResourcePermissions = true +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/operations-management/solution/README.md b/avm/res/operations-management/solution/README.md index 42365f2274..f8f05da8f6 100644 --- a/avm/res/operations-management/solution/README.md +++ b/avm/res/operations-management/solution/README.md @@ -56,7 +56,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -81,6 +81,23 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'Updates' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Microsoft solution_ This instance deploys the module with a Microsoft solution. @@ -110,7 +127,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -141,6 +158,25 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'AzureAutomation' +// Non-required parameters +param location = '' +param product = 'OMSGallery' +param publisher = 'Microsoft' +``` + +
+

+ ### Example 3: _Non-Microsoft solution_ This instance deploys the module with a third party (Non-Microsoft) solution. @@ -170,7 +206,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -201,6 +237,25 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'omsnonms001' +// Non-required parameters +param location = '' +param product = 'nonmsTestSolutionProduct' +param publisher = 'nonmsTestSolutionPublisher' +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -230,7 +285,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -261,6 +316,25 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'AzureAutomation' +// Non-required parameters +param location = '' +param product = 'OMSGallery' +param publisher = 'Microsoft' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/portal/dashboard/README.md b/avm/res/portal/dashboard/README.md index 07b61aa261..63cc4e5a9b 100644 --- a/avm/res/portal/dashboard/README.md +++ b/avm/res/portal/dashboard/README.md @@ -56,7 +56,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -236,7 +252,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -400,6 +416,154 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/portal/dashboard:' + +// Required parameters +param name = 'pdmax001' +// Non-required parameters +param lenses = [ + { + order: 0 + parts: [ + { + metadata: { + inputs: [] + type: 'Extension/Microsoft_Azure_Security/PartType/SecurityMetricGalleryTileViewModel' + } + position: { + colSpan: 2 + rowSpan: 3 + x: 0 + y: 0 + } + } + { + metadata: { + inputs: [ + { + isOptional: true + name: 'isShared' + } + { + isOptional: true + name: 'queryId' + } + { + isOptional: true + name: 'formatResults' + } + { + isOptional: true + name: 'partTitle' + value: 'Query 1' + } + { + isOptional: true + name: 'chartType' + value: 1 + } + { + isOptional: true + name: 'queryScope' + value: { + scope: 0 + values: [] + } + } + { + isOptional: true + name: 'query' + value: 'summarize ResourceCount=count() by type\n| order by ResourceCount desc\n| take 5\n| project [\'Resource Type\']=type, [\'Resource Count\']=ResourceCount' + } + ] + partHeader: { + subtitle: '' + title: 'Top 5 resource types' + } + settings: {} + type: 'Extension/HubsExtension/PartType/ArgQueryChartTile' + } + position: { + colSpan: 9 + rowSpan: 3 + x: 2 + y: 0 + } + } + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param metadata = { + model: { + filterLocale: { + value: 'en-us' + } + filters: { + value: { + MsPortalFx_TimeRange: { + displayCache: { + name: 'UTC Time' + value: 'Past 24 hours' + } + filteredPartIds: [] + model: { + format: 'utc' + granularity: 'auto' + relative: '24h' + } + } + } + } + timeRange: { + type: 'MsPortalFx.Composition.Configuration.ValueTypes.TimeRange' + value: { + relative: { + duration: 24 + timeUnit: 1 + } + } + } + } +} +param roleAssignments = [ + { + name: '15e2e690-5c9f-4cbf-9716-94ee73efab8b' + 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. @@ -547,7 +711,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -696,6 +860,143 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/portal/dashboard:' + +// Required parameters +param name = 'pdwaf001' +// Non-required parameters +param lenses = [ + { + order: 0 + parts: [ + { + metadata: { + inputs: [] + settings: { + content: { + src: 'https://www.youtube.com/watch?v=JbIMrJKW5N0' + subtitle: 'Learn more about AVM' + title: 'Azure Verified Modules (AVM) introduction' + } + } + type: 'Extension/HubsExtension/PartType/VideoPart' + } + position: { + colSpan: 6 + rowSpan: 4 + x: 0 + y: 0 + } + } + { + metadata: { + inputs: [] + type: 'Extension/Microsoft_AAD_IAM/PartType/UserManagementSummaryPart' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 6 + y: 0 + } + } + { + metadata: { + inputs: [] + settings: { + content: {} + } + type: 'Extension/HubsExtension/PartType/ClockPart' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 8 + y: 0 + } + } + { + metadata: { + inputs: [ + { + isOptional: true + name: 'selectedMenuItemId' + } + ] + type: 'Extension/HubsExtension/PartType/GalleryTile' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 6 + y: 2 + } + } + { + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/HelpAndSupportPart' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 8 + y: 2 + } + } + ] + } +] +param location = '' +param metadata = { + model: { + filterLocale: { + value: 'en-us' + } + filters: { + value: { + MsPortalFx_TimeRange: { + displayCache: { + name: 'UTC Time' + value: 'Past 24 hours' + } + filteredPartIds: [ + 'StartboardPart-MonitorChartPart-f6c2e060-fabc-4ce5-b031-45f3296510dd' + ] + model: { + format: 'utc' + granularity: 'auto' + relative: '24h' + } + } + } + } + timeRange: { + type: 'MsPortalFx.Composition.Configuration.ValueTypes.TimeRange' + value: { + relative: { + duration: 24 + timeUnit: 1 + } + } + } + } +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/power-bi-dedicated/capacity/README.md b/avm/res/power-bi-dedicated/capacity/README.md index b01901daba..c2f1039aab 100644 --- a/avm/res/power-bi-dedicated/capacity/README.md +++ b/avm/res/power-bi-dedicated/capacity/README.md @@ -62,7 +62,7 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -94,6 +94,28 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/power-bi-dedicated/capacity:' + +// Required parameters +param members = [ + '' +] +param name = 'pbdcapmin001' +param sku = { + capacity: 1 +} +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -155,7 +177,7 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +246,57 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/power-bi-dedicated/capacity:' + +// Required parameters +param members = [ + '' +] +param name = 'pbdcapmax001' +param sku = { + capacity: 1 + name: 'A1' + tier: 'PBIE_Azure' +} +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param mode = 'Gen2' +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: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -265,7 +338,7 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -310,6 +383,37 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/power-bi-dedicated/capacity:' + +// Required parameters +param members = [ + '' +] +param name = 'pbdcapwaf001' +param sku = { + capacity: 1 +} +// 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** diff --git a/avm/res/purview/account/README.md b/avm/res/purview/account/README.md index cc71dad4f6..7585844571 100644 --- a/avm/res/purview/account/README.md +++ b/avm/res/purview/account/README.md @@ -60,7 +60,7 @@ module account 'br/public:avm/res/purview/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module account 'br/public:avm/res/purview/account:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -267,7 +283,7 @@ module account 'br/public:avm/res/purview/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -472,6 +488,181 @@ module account 'br/public:avm/res/purview/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/purview/account:' + +// Required parameters +param name = 'pvamax001' +// Non-required parameters +param accountPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'account' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventHubPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + 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 = { + userAssignedResourceIds: [ + '' + ] +} +param managedResourceGroupName = 'pvamax001-managed-rg' +param portalPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'portal' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '8372742c-408e-4a8a-a748-aca787a0e33e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageBlobPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param storageQueuePrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'queue' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +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. @@ -578,7 +769,7 @@ module account 'br/public:avm/res/purview/account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -698,6 +889,102 @@ module account 'br/public:avm/res/purview/account:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/purview/account:' + +// Required parameters +param name = 'pvawaf001' +// Non-required parameters +param accountPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'account' + subnetResourceId: '' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventHubPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + } +] +param location = '' +param managedResourceGroupName = 'pvawaf001-managed-rg' +param portalPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'portal' + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param storageBlobPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } +] +param storageQueuePrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'queue' + subnetResourceId: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/recovery-services/vault/README.md b/avm/res/recovery-services/vault/README.md index 06c21b10e9..65477a4986 100644 --- a/avm/res/recovery-services/vault/README.md +++ b/avm/res/recovery-services/vault/README.md @@ -83,7 +83,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -121,6 +121,34 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = 'rsvmin001' +// Non-required parameters +param location = '' +param replicationAlertSettings = { + customEmailAddresses: [ + 'test.user@testcompany.com' + ] + locale: 'en-US' + sendToOwners: 'Send' +} +param securitySettings = { + immutabilitySettings: { + state: 'Unlocked' + } +} +``` + +
+

+ ### Example 2: _Test case for disaster recovery enabled_ This instance deploys the module with disaster recovery enabled. @@ -207,7 +235,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -295,6 +323,82 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = '' +// Non-required parameters +param location = '' +param replicationFabrics = [ + { + location: 'NorthEurope' + replicationContainers: [ + { + name: 'ne-container1' + replicationContainerMappings: [ + { + policyName: 'Default_values' + targetContainerName: 'pluto' + targetProtectionContainerId: '' + } + ] + } + { + name: 'ne-container2' + replicationContainerMappings: [ + { + policyName: 'Default_values' + targetContainerFabricName: 'WE-2' + targetContainerName: 'we-container1' + } + ] + } + ] + } + { + location: 'WestEurope' + name: 'WE-2' + replicationContainers: [ + { + name: 'we-container1' + replicationContainerMappings: [ + { + policyName: 'Default_values' + targetContainerFabricName: 'NorthEurope' + targetContainerName: 'ne-container2' + } + ] + } + ] + } +] +param replicationPolicies = [ + { + name: 'Default_values' + } + { + appConsistentFrequencyInMinutes: 240 + crashConsistentFrequencyInMinutes: 7 + multiVmSyncStatus: 'Disable' + name: 'Custom_values' + recoveryPointHistory: 2880 + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -686,7 +790,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1097,6 +1201,387 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = 'rsvmax001' +// Non-required parameters +param backupConfig = { + enhancedSecurityState: 'Disabled' + softDeleteFeatureState: 'Disabled' +} +param backupPolicies = [ + { + name: 'VMpolicy' + properties: { + backupManagementType: 'AzureIaasVM' + instantRPDetails: {} + instantRpRetentionRangeInDays: 2 + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 180 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 12 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T07:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + } + } + { + name: 'sqlpolicy' + properties: { + backupManagementType: 'AzureWorkload' + protectedItemsCount: 0 + settings: { + isCompression: true + issqlcompression: true + timeZone: 'UTC' + } + subProtectionPolicy: [ + { + policyType: 'Full' + retentionPolicy: { + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 104 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Sunday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2019-11-07T22:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Differential' + retentionPolicy: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Monday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2017-03-07T02:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Log' + retentionPolicy: { + retentionDuration: { + count: 15 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + scheduleFrequencyInMins: 120 + schedulePolicyType: 'LogSchedulePolicy' + } + } + ] + workLoadType: 'SQLDataBase' + } + } + { + name: 'filesharepolicy' + properties: { + backupManagementType: 'AzureStorage' + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T04:30:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T04:30:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + workloadType: 'AzureFileShare' + } + } +] +param backupStorageConfig = { + crossRegionRestoreFlag: true + storageModelType: 'GeoRedundant' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param monitoringSettings = { + azureMonitorAlertSettings: { + alertsForAllJobFailures: 'Enabled' + } + classicAlertSettings: { + alertsForCriticalOperations: 'Enabled' + } +} +param privateEndpoints = [ + { + ipConfigurations: [ + { + name: 'myIpConfig-1' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-tel1' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-2' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-prot2' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'myIPconfig-3' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-srs1' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'myIPconfig-4' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-rcm1' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'myIPconfig-5' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-id1' + privateIPAddress: '10.0.0.14' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param replicationAlertSettings = { + customEmailAddresses: [ + 'test.user@testcompany.com' + ] + locale: 'en-US' + sendToOwners: 'Send' +} +param roleAssignments = [ + { + name: '35288372-e6b4-4333-9ee6-dd997b96d52b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securitySettings = { + immutabilitySettings: { + state: 'Unlocked' + } +} +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. @@ -1469,7 +1954,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1859,6 +2344,368 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = 'rsvwaf001' +// Non-required parameters +param backupConfig = { + enhancedSecurityState: 'Disabled' + softDeleteFeatureState: 'Disabled' +} +param backupPolicies = [ + { + name: 'VMpolicy' + properties: { + backupManagementType: 'AzureIaasVM' + instantRPDetails: {} + instantRpRetentionRangeInDays: 2 + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 180 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 12 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T07:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + } + } + { + name: 'sqlpolicy' + properties: { + backupManagementType: 'AzureWorkload' + protectedItemsCount: 0 + settings: { + isCompression: true + issqlcompression: true + timeZone: 'UTC' + } + subProtectionPolicy: [ + { + policyType: 'Full' + retentionPolicy: { + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 104 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Sunday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2019-11-07T22:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Differential' + retentionPolicy: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Monday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2017-03-07T02:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Log' + retentionPolicy: { + retentionDuration: { + count: 15 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + scheduleFrequencyInMins: 120 + schedulePolicyType: 'LogSchedulePolicy' + } + } + ] + workLoadType: 'SQLDataBase' + } + } + { + name: 'filesharepolicy' + properties: { + backupManagementType: 'AzureStorage' + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T04:30:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T04:30:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + workloadType: 'AzureFileShare' + } + } +] +param backupStorageConfig = { + crossRegionRestoreFlag: true + storageModelType: 'GeoRedundant' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param monitoringSettings = { + azureMonitorAlertSettings: { + alertsForAllJobFailures: 'Enabled' + } + classicAlertSettings: { + alertsForCriticalOperations: 'Enabled' + } +} +param privateEndpoints = [ + { + ipConfigurations: [ + { + name: 'myIpConfig-1' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-tel1' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-2' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-prot2' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'myIPconfig-3' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-srs1' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'myIPconfig-4' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-rcm1' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'myIPconfig-5' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-id1' + privateIPAddress: '10.0.0.14' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param replicationAlertSettings = { + customEmailAddresses: [ + 'test.user@testcompany.com' + ] + locale: 'en-US' + sendToOwners: 'Send' +} +param securitySettings = { + immutabilitySettings: { + state: 'Unlocked' + } +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/relay/namespace/README.md b/avm/res/relay/namespace/README.md index 06c2c905d1..4059dd7c06 100644 --- a/avm/res/relay/namespace/README.md +++ b/avm/res/relay/namespace/README.md @@ -71,7 +71,7 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,22 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -255,7 +271,7 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -433,6 +449,158 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/relay/namespace:' + +// Required parameters +param name = 'rnmax001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param hybridConnections = [ + { + name: 'rnmaxhc001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + userMetadata: '[{\'key\':\'endpoint\',\'value\':\'db-server.constoso.com:1433\'}]' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + subnet: { + id: '' + ignoreMissingVnetServiceEndpoint: true + } + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'd3dff05a-96d7-4d63-82c2-0fd8ac7b859d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + 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' +} +param wcfRelays = [ + { + name: 'rnmaxwcf001' + relayType: 'NetTcp' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } +] +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -541,7 +709,7 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -659,6 +827,104 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/relay/namespace:' + +// Required parameters +param name = 'rnwaf001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param hybridConnections = [ + { + name: 'rnwafhc001' + userMetadata: '[{\'key\':\'endpoint\',\'value\':\'db-server.constoso.com:1433\'}]' + } +] +param location = '' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + subnet: { + id: '' + ignoreMissingVnetServiceEndpoint: true + } + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param wcfRelays = [ + { + name: 'rnwafwcf001' + relayType: 'NetTcp' + } +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/resource-graph/query/README.md b/avm/res/resource-graph/query/README.md index 316e8d7090..a77e9f432a 100644 --- a/avm/res/resource-graph/query/README.md +++ b/avm/res/resource-graph/query/README.md @@ -57,7 +57,7 @@ module query 'br/public:avm/res/resource-graph/query:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,23 @@ module query 'br/public:avm/res/resource-graph/query:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resource-graph/query:' + +// Required parameters +param name = 'rdsmin001' +param query = 'Resources | limit 10' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -137,7 +154,7 @@ module query 'br/public:avm/res/resource-graph/query:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -198,6 +215,51 @@ module query 'br/public:avm/res/resource-graph/query:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resource-graph/query:' + +// Required parameters +param name = 'rdsmax001' +param query = '' +// Non-required parameters +param location = '' +param lock = { + kind: 'None' +} +param queryDescription = 'An example query to list first 5 subscriptions.' +param roleAssignments = [ + { + name: '9634350c-b241-4481-8c22-4166891596ab' + 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. @@ -234,7 +296,7 @@ module query 'br/public:avm/res/resource-graph/query:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -274,6 +336,32 @@ module query 'br/public:avm/res/resource-graph/query:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resource-graph/query:' + +// Required parameters +param name = 'rdswaf001' +param query = 'resourcecontainers| where type == \'microsoft.resources/subscriptions\' | take 5' +// Non-required parameters +param location = '' +param lock = { + kind: 'None' +} +param queryDescription = 'An example query to list first 5 subscriptions.' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/resources/deployment-script/README.md b/avm/res/resources/deployment-script/README.md index a922e8496c..6cb35243e4 100644 --- a/avm/res/resources/deployment-script/README.md +++ b/avm/res/resources/deployment-script/README.md @@ -76,7 +76,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

-via JSON Parameter file +via JSON parameters file ```json { @@ -128,6 +128,38 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

+

+ +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.9.1' +param environmentVariables = [ + { + name: 'var1' + value: 'AVM Deployment Script test!' + } +] +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +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. @@ -162,7 +194,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

-via JSON Parameter file +via JSON parameters file ```json { @@ -200,6 +232,30 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

+

+ +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 = '9.7' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +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. @@ -278,7 +334,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

-via JSON Parameter file +via JSON parameters file ```json { @@ -382,6 +438,74 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

+

+ +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.9.1' +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 = { + userAssignedResourcesIds: [ + '' + ] +} +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. @@ -424,7 +548,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

-via JSON Parameter file +via JSON parameters file ```json { @@ -482,6 +606,38 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

+

+ +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.9.1' +param cleanupPreference = 'Always' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +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. @@ -524,7 +680,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

-via JSON Parameter file +via JSON parameters file ```json { @@ -582,6 +738,38 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

+

+ +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.9.1' +param cleanupPreference = 'Always' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +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. @@ -619,7 +807,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

-via JSON Parameter file +via JSON parameters file ```json { @@ -666,6 +854,33 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

+

+ +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 = '9.7' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +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. @@ -713,7 +928,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

-via JSON Parameter file +via JSON parameters file ```json { @@ -778,6 +993,43 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

+

+ +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.9.1' +param cleanupPreference = 'Always' +param location = '' +param lock = { + kind: 'None' +} +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +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** diff --git a/avm/res/resources/resource-group/README.md b/avm/res/resources/resource-group/README.md index bf87e88b4c..f2908dcd05 100644 --- a/avm/res/resources/resource-group/README.md +++ b/avm/res/resources/resource-group/README.md @@ -56,7 +56,7 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/resource-group:' + +// Required parameters +param name = 'avm-resources.resourcegroups-rrgmin-rg' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -132,7 +148,7 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +204,50 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

+

+ +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. @@ -223,7 +283,7 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +318,31 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

+

+ +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 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** diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md index e8645d04a5..056c76fef4 100644 --- a/avm/res/search/search-service/README.md +++ b/avm/res/search/search-service/README.md @@ -64,7 +64,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module searchService 'br/public:avm/res/search/search-service:' = {

+

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

+ ### Example 2: _Deploying with a key vault reference to save secrets_ This instance deploys the module saving admin key secrets in a key vault. @@ -123,7 +139,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -162,6 +178,33 @@ module searchService 'br/public:avm/res/search/search-service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'kv-ref' +// Non-required parameters +param authOptions = { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } +} +param disableLocalAuth = false +param location = '' +param secretsExportConfiguration = { + keyVaultResourceId: '' + primaryAdminKeyName: 'Primary-Admin-Key' + secondaryAdminKeyName: 'Secondary-Admin-Key' +} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -258,7 +301,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -378,6 +421,92 @@ module searchService 'br/public:avm/res/search/search-service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'sssmax001' +// Non-required parameters +param authOptions = { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } +} +param cmkEnforcement = 'Enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = false +param hostingMode = 'highDensity' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param networkRuleSet = { + ipRules: [ + { + value: '40.74.28.0/23' + } + { + value: '87.147.204.13' + } + ] +} +param partitionCount = 2 +param replicaCount = 3 +param roleAssignments = [ + { + name: '73ec30e0-2e25-475f-beec-d90cab332eb7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param semanticSearch = 'standard' +param sku = 'standard3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 4: _Private endpoint-enabled deployment_ This instance deploys the module with private endpoints. @@ -452,7 +581,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -530,6 +659,70 @@ module searchService 'br/public:avm/res/search/search-service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'ssspr001' +// Non-required parameters +param location = '' +param privateEndpoints = [ + { + applicationSecurityGroupResourceIds: [ + '' + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param sharedPrivateLinkResources = [ + { + groupId: 'blob' + privateLinkResourceId: '' + requestMessage: 'Please approve this request' + resourceRegion: '' + } + { + groupId: 'vault' + privateLinkResourceId: '' + requestMessage: 'Please approve this request' + } +] +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. @@ -603,7 +796,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -696,6 +889,69 @@ module searchService 'br/public:avm/res/search/search-service:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'ssswaf001' +// Non-required parameters +param authOptions = { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } +} +param cmkEnforcement = 'Enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = false +param hostingMode = 'highDensity' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param networkRuleSet = { + ipRules: [ + { + value: '40.74.28.0/23' + } + { + value: '87.147.204.13' + } + ] +} +param partitionCount = 2 +param replicaCount = 3 +param sku = 'standard3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/service-bus/namespace/README.md b/avm/res/service-bus/namespace/README.md index 178f3dd665..bce7d6853c 100644 --- a/avm/res/service-bus/namespace/README.md +++ b/avm/res/service-bus/namespace/README.md @@ -74,7 +74,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -102,6 +102,26 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnmin001' +// Non-required parameters +param location = '' +param skuObject = { + capacity: 2 + name: 'Premium' +} +``` + +
+

+ ### Example 2: _Using encryption parameter set_ This instance deploys the module with features enabled for CMK encryption. @@ -143,7 +163,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -186,6 +206,37 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] +} +param skuObject = { + capacity: 1 + name: 'Premium' +} +``` + +
+

+ ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -442,7 +493,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -724,6 +775,252 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnmax001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'RuntimeAuditLogs' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'diagnosticsetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] +} +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param premiumMessagingPartitions = 1 +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.namespace.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'namespace' + memberName: 'namespace' + privateIPAddress: '10.0.0.10' + } + } + ] + name: 'myPrivateEndpoint' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + privateLinkServiceConnectionName: 'customLinkName' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Enabled' +param queues = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + autoDeleteOnIdle: 'PT5M' + maxMessageSizeInKilobytes: 2048 + name: 'sbnmaxq001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +param roleAssignments = [ + { + name: '2c42f915-20bf-4094-ba42-fee1f811d374' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuObject = { + capacity: 16 + name: 'Premium' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + name: 'sbnmaxt001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subscriptions: [ + { + name: 'subscription001' + } + ] + } +] +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -885,7 +1182,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1072,6 +1369,157 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnwaf001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] +} +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param premiumMessagingPartitions = 1 +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Enabled' +param queues = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + autoDeleteOnIdle: 'PT5M' + maxMessageSizeInKilobytes: 2048 + name: 'sbnwafq001' + roleAssignments: [] + } +] +param roleAssignments = [] +param skuObject = { + capacity: 2 + name: 'Premium' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + name: 'sbnwaft001' + roleAssignments: [] + } +] +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/service-fabric/cluster/README.md b/avm/res/service-fabric/cluster/README.md index 08c89d43fa..de02d4aa07 100644 --- a/avm/res/service-fabric/cluster/README.md +++ b/avm/res/service-fabric/cluster/README.md @@ -79,7 +79,7 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -131,6 +131,44 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-fabric/cluster:' + +// Required parameters +param managementEndpoint = 'https://sfcmin001.westeurope.cloudapp.azure.com:19080' +param name = 'sfcmin001' +param nodeTypes = [ + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Bronze' + ephemeralPorts: { + endPort: 65534 + startPort: 49152 + } + httpGatewayEndpointPort: 19080 + isPrimary: true + name: 'Node01' + } +] +param reliabilityLevel = 'None' +// Non-required parameters +param certificate = { + thumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' +} +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -324,7 +362,7 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -547,6 +585,189 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-fabric/cluster:' + +// Required parameters +param managementEndpoint = 'https://sfcmax001.westeurope.cloudapp.azure.com:19080' +param name = 'sfcmax001' +param nodeTypes = [ + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Silver' + ephemeralPorts: { + endPort: 65534 + startPort: 49152 + } + httpGatewayEndpointPort: 19080 + isPrimary: true + isStateless: false + multipleAvailabilityZones: false + name: 'Node01' + placementProperties: {} + reverseProxyEndpointPort: '' + vmInstanceCount: 5 + } + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Bronze' + ephemeralPorts: { + endPort: 64000 + httpGatewayEndpointPort: 19007 + isPrimary: true + name: 'Node02' + startPort: 49000 + vmInstanceCount: 5 + } + } +] +param reliabilityLevel = 'Silver' +// Non-required parameters +param addOnFeatures = [ + 'BackupRestoreService' + 'DnsService' + 'RepairManager' + 'ResourceMonitorService' +] +param applicationTypes = [ + { + name: 'WordCount' + } +] +param azureActiveDirectory = { + clientApplication: '' + clusterApplication: 'cf33fea8-b30f-424f-ab73-c48d99e0b222' + tenantId: '' +} +param certificateCommonNames = { + commonNames: [ + { + certificateCommonName: 'certcommon' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + } + ] + x509StoreName: 'My' +} +param clientCertificateCommonNames = [ + { + certificateCommonName: 'clientcommoncert1' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + isAdmin: false + } + { + certificateCommonName: 'clientcommoncert2' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC131' + isAdmin: false + } +] +param diagnosticsStorageAccountConfig = { + blobEndpoint: '' + protectedAccountKeyName: 'StorageAccountKey1' + queueEndpoint: '' + storageAccountName: '' + tableEndpoint: '' +} +param fabricSettings = [ + { + name: 'Security' + parameters: [ + { + name: 'ClusterProtectionLevel' + value: 'EncryptAndSign' + } + ] + } + { + name: 'UpgradeService' + parameters: [ + { + name: 'AppPollIntervalInSeconds' + value: '60' + } + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maxUnusedVersionsToKeep = 2 +param notifications = [ + { + isEnabled: true + notificationCategory: 'WaveProgress' + notificationLevel: 'Critical' + notificationTargets: [ + { + notificationChannel: 'EmailUser' + receivers: [ + 'SomeReceiver' + ] + } + ] + } +] +param roleAssignments = [ + { + name: '26b52f01-eebc-4056-a516-41541369258c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + clusterName: 'sfcmax001' + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Service Fabric' +} +param upgradeDescription = { + deltaHealthPolicy: { + maxPercentDeltaUnhealthyApplications: 0 + maxPercentDeltaUnhealthyNodes: 0 + maxPercentUpgradeDomainDeltaUnhealthyNodes: 0 + } + forceRestart: false + healthCheckRetryTimeout: '00:45:00' + healthCheckStableDuration: '00:01:00' + healthCheckWaitDuration: '00:00:30' + healthPolicy: { + maxPercentUnhealthyApplications: 0 + maxPercentUnhealthyNodes: 0 + } + upgradeDomainTimeout: '02:00:00' + upgradeReplicaSetCheckTimeout: '1.00:00:00' + upgradeTimeout: '02:00:00' +} +param vmImage = 'Linux' +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -712,7 +933,7 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -903,6 +1124,161 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-fabric/cluster:' + +// Required parameters +param managementEndpoint = 'https://sfcwaf001.westeurope.cloudapp.azure.com:19080' +param name = 'sfcwaf001' +param nodeTypes = [ + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Silver' + ephemeralPorts: { + endPort: 65534 + startPort: 49152 + } + httpGatewayEndpointPort: 19080 + isPrimary: true + isStateless: false + multipleAvailabilityZones: false + name: 'Node01' + placementProperties: {} + reverseProxyEndpointPort: '' + vmInstanceCount: 5 + } + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Bronze' + ephemeralPorts: { + endPort: 64000 + httpGatewayEndpointPort: 19007 + isPrimary: true + name: 'Node02' + startPort: 49000 + vmInstanceCount: 5 + } + } +] +param reliabilityLevel = 'Silver' +// Non-required parameters +param addOnFeatures = [ + 'BackupRestoreService' + 'DnsService' + 'RepairManager' + 'ResourceMonitorService' +] +param applicationTypes = [ + { + name: 'WordCount' + } +] +param azureActiveDirectory = { + clientApplication: '' + clusterApplication: 'cf33fea8-b30f-424f-ab73-c48d99e0b222' + tenantId: '' +} +param certificate = { + thumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + x509StoreName: 'My' +} +param clientCertificateCommonNames = [ + { + certificateCommonName: 'clientcommoncert1' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + isAdmin: false + } + { + certificateCommonName: 'clientcommoncert2' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC131' + isAdmin: false + } +] +param diagnosticsStorageAccountConfig = { + blobEndpoint: '' + protectedAccountKeyName: 'StorageAccountKey1' + queueEndpoint: '' + storageAccountName: '' + tableEndpoint: '' +} +param fabricSettings = [ + { + name: 'Security' + parameters: [ + { + name: 'ClusterProtectionLevel' + value: 'EncryptAndSign' + } + ] + } + { + name: 'UpgradeService' + parameters: [ + { + name: 'AppPollIntervalInSeconds' + value: '60' + } + ] + } +] +param location = '' +param maxUnusedVersionsToKeep = 2 +param notifications = [ + { + isEnabled: true + notificationCategory: 'WaveProgress' + notificationLevel: 'Critical' + notificationTargets: [ + { + notificationChannel: 'EmailUser' + receivers: [ + 'SomeReceiver' + ] + } + ] + } +] +param tags = { + clusterName: 'sfcwaf001' + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Service Fabric' +} +param upgradeDescription = { + deltaHealthPolicy: { + maxPercentDeltaUnhealthyApplications: 0 + maxPercentDeltaUnhealthyNodes: 0 + maxPercentUpgradeDomainDeltaUnhealthyNodes: 0 + } + forceRestart: false + healthCheckRetryTimeout: '00:45:00' + healthCheckStableDuration: '00:01:00' + healthCheckWaitDuration: '00:00:30' + healthPolicy: { + maxPercentUnhealthyApplications: 0 + maxPercentUnhealthyNodes: 0 + } + upgradeDomainTimeout: '02:00:00' + upgradeReplicaSetCheckTimeout: '1.00:00:00' + upgradeTimeout: '02:00:00' +} +param vmImage = 'Linux' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/service-networking/traffic-controller/README.md b/avm/res/service-networking/traffic-controller/README.md index ce5cb08d93..c85a18a11b 100644 --- a/avm/res/service-networking/traffic-controller/README.md +++ b/avm/res/service-networking/traffic-controller/README.md @@ -60,7 +60,7 @@ module trafficController 'br/public:avm/res/service-networking/traffic-controlle

-via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module trafficController 'br/public:avm/res/service-networking/traffic-controlle

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-networking/traffic-controller:' + +// Required parameters +param name = 'sntcmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -164,7 +180,7 @@ module trafficController 'br/public:avm/res/service-networking/traffic-controlle

-via JSON Parameter file +via JSON parameters file ```json { @@ -254,6 +270,78 @@ module trafficController 'br/public:avm/res/service-networking/traffic-controlle

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-networking/traffic-controller:' + +// Required parameters +param name = 'sntcmax001' +// Non-required parameters +param associations = [ + { + name: 'association1' + subnetResourceId: '' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param frontends = [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'a6931c52-0b79-4fe9-ad3d-72188dfff379' + 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. @@ -307,7 +395,7 @@ module trafficController 'br/public:avm/res/service-networking/traffic-controlle

-via JSON Parameter file +via JSON parameters file ```json { @@ -364,6 +452,49 @@ module trafficController 'br/public:avm/res/service-networking/traffic-controlle

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-networking/traffic-controller:' + +// Required parameters +param name = 'sntcwaf001' +// Non-required parameters +param associations = [ + { + name: 'association1' + subnetResourceId: '' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param frontends = [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/signal-r-service/signal-r/README.md b/avm/res/signal-r-service/signal-r/README.md index 9d3688a0d3..3612033f31 100644 --- a/avm/res/signal-r-service/signal-r/README.md +++ b/avm/res/signal-r-service/signal-r/README.md @@ -64,7 +64,7 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/signal-r:' + +// Required parameters +param name = 'srsdrmin-001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -196,7 +212,7 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -326,6 +342,106 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/signal-r:' + +// Required parameters +param name = 'srssrmax-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param kind = 'SignalR' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srssrmax-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param roleAssignments = [ + { + name: 'd8c98876-5377-4b49-98ae-41a8b5537761' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Standard_S1' +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. @@ -403,7 +519,7 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -496,6 +612,73 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/signal-r:' + +// Required parameters +param name = 'srssrwaf-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param kind = 'SignalR' +param location = '' +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srssrwaf-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param sku = 'Standard_S1' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/signal-r-service/web-pub-sub/README.md b/avm/res/signal-r-service/web-pub-sub/README.md index e255f3e70c..c060863897 100644 --- a/avm/res/signal-r-service/web-pub-sub/README.md +++ b/avm/res/signal-r-service/web-pub-sub/README.md @@ -64,7 +64,7 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/web-pub-sub:' + +// Required parameters +param name = 'srswpsmin-001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -199,7 +215,7 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -332,6 +348,109 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/web-pub-sub:' + +// Required parameters +param name = 'srswpsmax-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srswpsmax-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'webpubsub' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param roleAssignments = [ + { + name: '8e40bf2f-0457-4292-a83a-eedc36d04f6a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Standard_S1' +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. @@ -412,7 +531,7 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -508,6 +627,76 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/web-pub-sub:' + +// Required parameters +param name = 'srswpswaf-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param location = '' +param managedIdentities = { + systemAssigned: true +} +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srswpswaf-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'webpubsub' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param sku = 'Standard_S1' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/sql/instance-pool/README.md b/avm/res/sql/instance-pool/README.md index 544047ed12..2437ec09f2 100644 --- a/avm/res/sql/instance-pool/README.md +++ b/avm/res/sql/instance-pool/README.md @@ -54,7 +54,7 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,23 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/instance-pool:' + +// Required parameters +param name = '' +param subnetResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -107,7 +124,7 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -135,6 +152,24 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/instance-pool:' + +// Required parameters +param name = '' +param subnetResourceId = '' +// Non-required parameters +param location = '' +param skuName = 'GP_Gen8IM' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/sql/managed-instance/README.md b/avm/res/sql/managed-instance/README.md index 4efc05d72d..a255e2ff20 100644 --- a/avm/res/sql/managed-instance/README.md +++ b/avm/res/sql/managed-instance/README.md @@ -69,7 +69,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -100,6 +100,25 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmimin' +param subnetResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -234,7 +253,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -412,6 +431,130 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmimax' +param subnetResourceId = '' +// Non-required parameters +param collation = 'SQL_Latin1_General_CP1_CI_AS' +param databases = [ + { + backupLongTermRetentionPolicies: { + name: 'default' + } + backupShortTermRetentionPolicies: { + name: 'default' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'sqlmimax-db-001' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsZonePartner = '' +param encryptionProtectorObj = { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' +} +param hardwareFamily = 'Gen5' +param keys = [ + { + name: '' + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param licenseType = 'LicenseIncluded' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param proxyOverride = 'Proxy' +param publicDataEndpointEnabled = false +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securityAlertPoliciesObj = { + emailAccountAdmins: true + name: 'default' + state: 'Enabled' +} +param servicePrincipal = 'SystemAssigned' +param skuName = 'GP_Gen5' +param skuTier = 'GeneralPurpose' +param storageSizeInGB = 32 +param timezoneId = 'UTC' +param vCores = 4 +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +``` + +
+

+ ### Example 3: _With vulnerability assessment_ This instance deploys the module with a vulnerability assessment. @@ -466,7 +609,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -528,6 +671,50 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmivln' +param subnetResourceId = '' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true +} +param securityAlertPoliciesObj = { + emailAccountAdmins: true + name: 'default' + state: 'Enabled' +} +param vulnerabilityAssessmentsObj = { + createStorageRoleAssignment: true + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + useStorageAccountAccessKey: false +} +``` + +
+

+ ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -645,7 +832,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -804,6 +991,113 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmiwaf' +param subnetResourceId = '' +// Non-required parameters +param collation = 'SQL_Latin1_General_CP1_CI_AS' +param databases = [ + { + backupLongTermRetentionPolicies: { + name: 'default' + } + backupShortTermRetentionPolicies: { + name: 'default' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'sqlmiwaf-db-001' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsZonePartner = '' +param encryptionProtectorObj = { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' +} +param hardwareFamily = 'Gen5' +param keys = [ + { + name: '' + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param licenseType = 'LicenseIncluded' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param proxyOverride = 'Proxy' +param publicDataEndpointEnabled = false +param securityAlertPoliciesObj = { + emailAccountAdmins: true + name: 'default' + state: 'Enabled' +} +param servicePrincipal = 'SystemAssigned' +param skuName = 'GP_Gen5' +param skuTier = 'GeneralPurpose' +param storageSizeInGB = 32 +param timezoneId = 'UTC' +param vCores = 4 +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index dcc3f4e02f..e38347c937 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -82,7 +82,7 @@ module server 'br/public:avm/res/sql/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -112,6 +112,28 @@ module server 'br/public:avm/res/sql/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsadmin' +// Non-required parameters +param administrators = { + azureADOnlyAuthentication: true + login: 'myspn' + principalType: 'Application' + sid: '' +} +param location = '' +``` + +
+

+ ### Example 2: _With audit settings_ This instance deploys the module with auditing settings. @@ -148,7 +170,7 @@ module server 'br/public:avm/res/sql/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +210,32 @@ module server 'br/public:avm/res/sql/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'ssaud001' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param auditSettings = { + isManagedIdentityInUse: true + state: 'Enabled' + storageAccountResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
+

+ ### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -216,7 +264,7 @@ module server 'br/public:avm/res/sql/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -244,6 +292,24 @@ module server 'br/public:avm/res/sql/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'ssmin001' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param location = '' +``` + +
+

+ ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -413,7 +479,7 @@ module server 'br/public:avm/res/sql/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -608,6 +674,165 @@ module server 'br/public:avm/res/sql/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsmax' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param databases = [ + { + backupLongTermRetentionPolicy: { + monthlyRetention: 'P6M' + } + backupShortTermRetentionPolicy: { + retentionDays: 14 + } + collation: 'SQL_Latin1_General_CP1_CI_AS' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + elasticPoolId: '' + encryptionProtectorObj: { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' + } + licenseType: 'LicenseIncluded' + maxSizeBytes: 34359738368 + name: 'sqlsmaxdb-001' + skuCapacity: 0 + skuName: 'ElasticPool' + skuTier: 'GeneralPurpose' + } +] +param elasticPools = [ + { + maintenanceConfigurationId: '' + name: 'sqlsmax-ep-001' + skuCapacity: 10 + skuName: 'GP_Gen5' + skuTier: 'GeneralPurpose' + } +] +param firewallRules = [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } +] +param keys = [ + { + name: '' + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param restrictOutboundNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '7027a5c5-d1b1-49e0-80cc-ffdff3a3ada9' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securityAlertPolicies = [ + { + emailAccountAdmins: true + name: 'Default' + state: 'Enabled' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkRules = [ + { + ignoreMissingVnetServiceEndpoint: true + name: 'newVnetRule1' + virtualNetworkSubnetId: '' + } +] +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' +} +``` + +
+

+ ### Example 5: _With a secondary database_ This instance deploys the module with a secondary database. @@ -651,7 +876,7 @@ module server 'br/public:avm/res/sql/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -698,6 +923,39 @@ module server 'br/public:avm/res/sql/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsec-sec' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param databases = [ + { + createMode: 'Secondary' + maxSizeBytes: 2147483648 + name: '' + skuName: 'Basic' + skuTier: 'Basic' + sourceDatabaseResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ### Example 6: _With vulnerability assessment_ This instance deploys the module with a vulnerability assessment. @@ -757,7 +1015,7 @@ module server 'br/public:avm/res/sql/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -826,6 +1084,55 @@ module server 'br/public:avm/res/sql/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsvln' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param securityAlertPolicies = [ + { + emailAccountAdmins: true + name: 'Default' + state: 'Enabled' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vulnerabilityAssessmentsObj = { + createStorageRoleAssignment: true + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + useStorageAccountAccessKey: false +} +``` + +
+

+ ### Example 7: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -960,7 +1267,7 @@ module server 'br/public:avm/res/sql/server:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1112,6 +1419,130 @@ module server 'br/public:avm/res/sql/server:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlswaf' +// Non-required parameters +param administrators = { + azureADOnlyAuthentication: true + login: 'myspn' + principalType: 'Application' + sid: '' + tenantId: '' +} +param databases = [ + { + backupLongTermRetentionPolicy: { + monthlyRetention: 'P6M' + } + backupShortTermRetentionPolicy: { + retentionDays: 14 + } + collation: 'SQL_Latin1_General_CP1_CI_AS' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + elasticPoolId: '' + encryptionProtectorObj: { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' + } + licenseType: 'LicenseIncluded' + maxSizeBytes: 34359738368 + name: 'sqlswafdb-001' + skuCapacity: 0 + skuName: 'ElasticPool' + skuTier: 'GeneralPurpose' + } +] +param elasticPools = [ + { + maintenanceConfigurationId: '' + name: 'sqlswaf-ep-001' + skuCapacity: 10 + skuName: 'GP_Gen5' + skuTier: 'GeneralPurpose' + } +] +param keys = [ + { + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'sqlServer' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param restrictOutboundNetworkAccess = 'Disabled' +param securityAlertPolicies = [ + { + emailAccountAdmins: true + name: 'Default' + state: 'Enabled' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkRules = [ + { + ignoreMissingVnetServiceEndpoint: true + name: 'newVnetRule1' + virtualNetworkSubnetId: '' + } +] +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/storage/storage-account/README.md b/avm/res/storage/storage-account/README.md index 8422599676..b5105ee977 100644 --- a/avm/res/storage/storage-account/README.md +++ b/avm/res/storage/storage-account/README.md @@ -83,7 +83,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -111,6 +111,24 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -139,7 +157,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -167,6 +185,24 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -197,7 +233,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +263,26 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -258,7 +314,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -289,6 +345,27 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -322,7 +399,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -353,6 +430,29 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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 = { + accessKey1: 'custom-key1-name' + accessKey2: 'custom-key2-name' + connectionString1: 'custom-connectionString1-name' + connectionString2: 'custom-connectionString2-name' + keyVaultResourceId: '' +} +``` + +
+

+ ### Example 6: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -799,7 +899,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1283,6 +1383,442 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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 + enableWORM: true + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + WORMRetention: 666 + } + ] + 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' + 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' + } + ] + storageAccountName: 'ssamax001' + } +] +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 = { + 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 = { + 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. @@ -1319,7 +1855,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1357,6 +1893,32 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -1411,7 +1973,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1469,6 +2031,50 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -1530,7 +2136,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1597,6 +2203,57 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -1624,7 +2281,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1649,6 +2306,23 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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. @@ -1913,7 +2587,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -2211,6 +2885,260 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

+

+ +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 + enableWORM: true + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + WORMRetention: 666 + } + ] + 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' + } + ] + storageAccountName: 'ssawaf001' + } +] +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** diff --git a/avm/res/synapse/private-link-hub/README.md b/avm/res/synapse/private-link-hub/README.md index 9a2123c05e..d0dba94113 100644 --- a/avm/res/synapse/private-link-hub/README.md +++ b/avm/res/synapse/private-link-hub/README.md @@ -64,7 +64,7 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/private-link-hub:' + +// Required parameters +param name = 'splhmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -162,7 +178,7 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -242,6 +258,72 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/private-link-hub:' + +// Required parameters +param name = 'splhmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '049a8b5a-70dc-4749-965c-b009733cf432' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + } +] +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. @@ -291,7 +373,7 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -340,6 +422,45 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/private-link-hub:' + +// Required parameters +param name = 'splhwaf001' +// Non-required parameters +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Web' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/synapse/workspace/README.md b/avm/res/synapse/workspace/README.md index 45cccee622..5e52048a3a 100644 --- a/avm/res/synapse/workspace/README.md +++ b/avm/res/synapse/workspace/README.md @@ -77,7 +77,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -108,6 +108,25 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swmin001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using encryption with Customer-Managed-Key_ This instance deploys the module using Customer-Managed-Keys using a System-Assigned Identity to access the Customer-Managed-Key secret. @@ -142,7 +161,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -182,6 +201,30 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swensa001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param encryptionActivateWorkspace = true +param location = '' +``` + +
+

+ ### Example 3: _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. @@ -216,7 +259,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -254,6 +297,30 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swenua001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +``` + +
+

+ ### Example 4: _Using firewall rules_ This instance deploys the module with the configuration of firewall rules. @@ -295,7 +362,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -340,6 +407,37 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swfwr001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param firewallRules = [ + { + endIpAddress: '87.14.134.20' + name: 'fwrule01' + startIpAddress: '87.14.134.20' + } + { + endIpAddress: '87.14.134.22' + name: 'fwrule02' + startIpAddress: '87.14.134.21' + } +] +param location = '' +``` + +
+

+ ### Example 5: _Using managed Vnet_ This instance deploys the module using a managed Vnet. @@ -374,7 +472,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -416,6 +514,30 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swmanv001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param allowedAadTenantIdsForLinking = [ + '' +] +param location = '' +param managedVirtualNetwork = true +param preventDataExfiltration = true +``` + +
+

+ ### Example 6: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -560,7 +682,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -722,6 +844,140 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swmax001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param administrator = { + administratorType: 'ServicePrincipal' + login: 'dep-msi-swmax' + sid: '' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'SynapseRbacOperations' + } + { + category: 'SynapseLinkEvent' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param initialWorkspaceAdminObjectID = '' +param integrationRuntimes = [ + { + name: 'shir01' + type: 'SelfHosted' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param managedVirtualNetwork = true +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SQL' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SQL' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SqlOnDemand' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Dev' + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '499f9243-2170-4204-807d-ee6d0f94a0d0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
+

+ ### Example 7: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -798,7 +1054,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -886,6 +1142,72 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swwaf001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'SynapseRbacOperations' + } + { + category: 'SynapseLinkEvent' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param integrationRuntimes = [ + { + name: 'shir01' + type: 'SelfHosted' + } +] +param location = '' +param managedVirtualNetwork = true +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SQL' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/virtual-machine-images/image-template/README.md b/avm/res/virtual-machine-images/image-template/README.md index b40afc22f9..22bfaaa10a 100644 --- a/avm/res/virtual-machine-images/image-template/README.md +++ b/avm/res/virtual-machine-images/image-template/README.md @@ -17,7 +17,7 @@ This module deploys a Virtual Machine Image Template that can be consumed by Azu | :-- | :-- | | `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` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/imageTemplates) | +| `Microsoft.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2023-07-01/imageTemplates) | ## Usage examples @@ -75,7 +75,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template: -

via JSON Parameter file +via JSON parameters file ```json { @@ -121,6 +121,40 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:

+

+ +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. @@ -247,7 +281,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template: -

via JSON Parameter file +via JSON parameters file ```json { @@ -399,6 +433,122 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:

+

+ +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 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 location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +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. @@ -455,7 +605,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template: -

via JSON Parameter file +via JSON parameters file ```json { @@ -519,6 +669,52 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:

+

+ +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** diff --git a/avm/res/web/connection/README.md b/avm/res/web/connection/README.md index be084c468f..a192ce132b 100644 --- a/avm/res/web/connection/README.md +++ b/avm/res/web/connection/README.md @@ -65,7 +65,7 @@ module connection 'br/public:avm/res/web/connection:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -95,6 +95,26 @@ module connection 'br/public:avm/res/web/connection:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/connection:' + +// Required parameters +param displayName = 'azuremonitorlogs' +param name = 'azuremonitor' +// Non-required parameters +param api = { + id: '' +} +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -153,7 +173,7 @@ module connection 'br/public:avm/res/web/connection:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -217,6 +237,54 @@ module connection 'br/public:avm/res/web/connection:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/connection:' + +// Required parameters +param displayName = 'azuremonitorlogs' +param name = 'azuremonitor' +// Non-required parameters +param api = { + id: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '396667c8-de54-4dcb-916a-72af71359f34' + 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. @@ -252,7 +320,7 @@ module connection 'br/public:avm/res/web/connection:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -289,6 +357,31 @@ module connection 'br/public:avm/res/web/connection:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/connection:' + +// Required parameters +param displayName = 'azuremonitorlogs' +param name = 'azuremonitor' +// Non-required parameters +param api = { + id: '' +} +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/web/hosting-environment/README.md b/avm/res/web/hosting-environment/README.md index 568d1fbb7b..d47314ce86 100644 --- a/avm/res/web/hosting-environment/README.md +++ b/avm/res/web/hosting-environment/README.md @@ -60,7 +60,7 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,24 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/hosting-environment:' + +// Required parameters +param name = 'whemin001' +param subnetResourceId = '' +// Non-required parameters +param kind = 'ASEv3' +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -171,7 +189,7 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -282,6 +300,79 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/hosting-environment:' + +// Required parameters +param name = 'whemax001' +param subnetResourceId = '' +// Non-required parameters +param allowNewPrivateEndpointConnections = true +param clusterSettings = [ + { + name: 'DisableTls1.0' + value: '1' + } +] +param customDnsSuffix = 'internal.contoso.com' +param customDnsSuffixCertificateUrl = '' +param customDnsSuffixKeyVaultReferenceIdentity = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param ftpEnabled = true +param inboundIpAddressOverride = '10.0.0.10' +param internalLoadBalancingMode = 'Web, Publishing' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param remoteDebugEnabled = true +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + hostingEnvironmentName: 'whemax001' + resourceType: 'App Service Environment' +} +param upgradePreference = 'Late' +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -344,7 +435,7 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

-via JSON Parameter file +via JSON parameters file ```json { @@ -430,6 +521,58 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/hosting-environment:' + +// Required parameters +param name = 'whewaf001' +param subnetResourceId = '' +// Non-required parameters +param allowNewPrivateEndpointConnections = true +param clusterSettings = [ + { + name: 'DisableTls1.0' + value: '1' + } +] +param customDnsSuffix = 'internal.contoso.com' +param customDnsSuffixCertificateUrl = '' +param customDnsSuffixKeyVaultReferenceIdentity = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param ftpEnabled = true +param inboundIpAddressOverride = '10.0.0.10' +param internalLoadBalancingMode = 'Web, Publishing' +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param remoteDebugEnabled = true +param tags = { + 'hidden-title': 'This is visible in the resource name' + hostingEnvironmentName: 'whewaf001' + resourceType: 'App Service Environment' +} +param upgradePreference = 'Late' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/web/serverfarm/README.md b/avm/res/web/serverfarm/README.md index 152351ffe2..11fee06158 100644 --- a/avm/res/web/serverfarm/README.md +++ b/avm/res/web/serverfarm/README.md @@ -57,7 +57,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

+

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

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -150,7 +166,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -235,6 +251,67 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/serverfarm:' + +// Required parameters +param name = 'wsfmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingwsfmax' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param kind = 'App' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param perSiteScaling = true +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 3 +param skuName = 'P1v3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneRedundant = true +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. Note - whilst this test is WAF aligned, zoneRedundant is set to false to avoid temporary AVM environment challenges. It is highly recommended that users of this module set the property value to true. @@ -288,7 +365,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -351,6 +428,49 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/serverfarm:' + +// Required parameters +param name = 'wsfwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingwsfwaf' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param kind = 'App' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param skuCapacity = 3 +param skuName = 'P1v3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneRedundant = true +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/web/site/README.md b/avm/res/web/site/README.md index 12c8a2371f..cbe8ec8fd9 100644 --- a/avm/res/web/site/README.md +++ b/avm/res/web/site/README.md @@ -81,7 +81,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -109,6 +109,24 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'functionapp' +param name = 'wsfamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Function App, using large parameter set_ This instance deploys the module as Function App with most of its features enabled. @@ -299,7 +317,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -517,6 +535,186 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'functionapp' +param name = 'wsfamax001' +param serverFarmResourceId = '' +// Non-required parameters +param appInsightResourceId = '' +param appSettingsKeyValuePairs = { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + EASYAUTH_SECRET: '' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' +} +authSettingV2Configuration: { + globalValidation: { + requireAuthentication: true + unauthenticatedClientAction: 'Return401' + } + httpSettings: { + forwardProxy: { + convention: 'NoProxy' + } + requireHttps: true + routes: { + apiPrefix: '/.auth' + } + } + identityProviders: { + azureActiveDirectory: { + enabled: true + login: { + disableWWWAuthenticate: false + } + registration: { + clientId: 'd874dd2f-2032-4db1-a053-f0ec243685aa' + clientSecretSettingName: 'EASYAUTH_SECRET' + openIdIssuer: '' + } + validation: { + allowedAudiences: [ + 'api://d874dd2f-2032-4db1-a053-f0ec243685aa' + ] + defaultAuthorizationPolicy: { + allowedPrincipals: {} + } + jwtClaimChecks: {} + } + } + } + login: { + allowedExternalRedirectUrls: [ + 'string' + ] + cookieExpiration: { + convention: 'FixedTime' + timeToExpiration: '08:00:00' + } + nonce: { + nonceExpirationInterval: '00:05:00' + validateNonce: true + } + preserveUrlFragmentsForLogins: false + routes: {} + tokenStore: { + azureBlobStorage: {} + enabled: true + fileSystem: {} + tokenRefreshExtensionHours: 72 + } + } + platform: { + enabled: true + runtimeVersion: '~1' + } +} +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param hybridConnectionRelays = [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } +] +param keyVaultAccessIdentityResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '9efc9c10-f482-4af0-9acb-03b5a16f947e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param siteConfig = { + alwaysOn: true + use32BitWorkerProcess: false +} +param storageAccountResourceId = '' +param storageAccountUseIdentityAuthentication = true +``` + +
+

+ ### Example 3: _Function App, using only defaults_ This instance deploys the module as Function App with the minimum set of required parameters. @@ -550,7 +748,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -585,6 +783,29 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'functionapp' +param name = 'wsfaset001' +param serverFarmResourceId = '' +// Non-required parameters +param appSettingsKeyValuePairs = { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' +} +param location = '' +``` + +
+

+ ### Example 4: _Web App, using only defaults_ This instance deploys the module as a Linux Web App with the minimum set of required parameters. @@ -622,7 +843,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -661,6 +882,33 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,linux,container' +param name = 'wslwamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +param siteConfig = { + appSettings: [ + { + name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' + value: 'false' + } + ] + linuxFxVersion: 'DOCKER|mcr.microsoft.com/appsvc/staticsite:latest' +} +``` + +
+

+ ### Example 5: _Web App_ This instance deploys the module as Web App with the set of logs configuration. @@ -722,7 +970,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -793,6 +1041,57 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wslc001' +param serverFarmResourceId = '' +// Non-required parameters +param appInsightResourceId = '' +param appSettingsKeyValuePairs = { + ENABLE_ORYX_BUILD: 'True' + JAVA_OPTS: '' + SCM_DO_BUILD_DURING_DEPLOYMENT: 'True' +} +param location = '' +param logsConfiguration = { + applicationLogs: { + fileSystem: { + level: 'Verbose' + } + } + detailedErrorMessages: { + enabled: true + } + failedRequestsTracing: { + enabled: true + } + httpLogs: { + fileSystem: { + enabled: true + retentionInDays: 1 + retentionInMb: 35 + } + } +} +param managedIdentities = { + systemAssigned: true +} +param siteConfig = { + alwaysOn: true + appCommandLine: '' +} +``` + +
+

+ ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -855,7 +1154,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -935,6 +1234,58 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswaf001' +param serverFarmResourceId = '' +// Non-required parameters +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param httpsOnly = true +param location = '' +param publicNetworkAccess = 'Disabled' +param scmSiteAlsoStopped = true +param siteConfig = { + alwaysOn: true + healthCheckPath: '/healthz' + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] +} +param vnetContentShareEnabled = true +param vnetImagePullEnabled = true +param vnetRouteAllEnabled = true +``` + +
+

+ ### Example 7: _Web App, using only defaults_ This instance deploys the module as Web App with the minimum set of required parameters. @@ -963,7 +1314,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -991,6 +1342,24 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 8: _Web App, using large parameter set_ This instance deploys the module as Web App with most of its features enabled. @@ -1208,7 +1577,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1459,6 +1828,213 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswamax001' +param serverFarmResourceId = '' +// Non-required parameters +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param httpsOnly = true +param hybridConnectionRelays = [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '0c2c82ef-069c-4085-b1bc-01614e0aa5ff' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scmSiteAlsoStopped = true +param siteConfig = { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] +} +param slots = [ + { + basicPublishingCredentialsPolicies: [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + hybridConnectionRelays: [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } + ] + name: 'slot1' + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'sites-slot1' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + name: '845ed19c-78e7-4422-aa3d-b78b67cd78a2' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + siteConfig: { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] + } + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } + { + basicPublishingCredentialsPolicies: [ + { + name: 'ftp' + } + { + name: 'scm' + } + ] + name: 'slot2' + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } +] +param storageAccountResourceId = '' +param storageAccountUseIdentityAuthentication = true +param vnetContentShareEnabled = true +param vnetImagePullEnabled = true +param vnetRouteAllEnabled = true +``` + +
+

+ ### Example 9: _Web App, using only defaults_ This instance deploys the module as a Linux Web App with the minimum set of required parameters. @@ -1487,7 +2063,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1515,6 +2091,24 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,linux' +param name = 'wswalmin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 10: _Web App, using large parameter set_ This instance deploys the module asa Linux Web App with most of its features enabled. @@ -1729,7 +2323,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -1977,6 +2571,210 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,linux' +param name = 'wswalmax001' +param serverFarmResourceId = '' +// Non-required parameters +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param httpsOnly = true +param hybridConnectionRelays = [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scmSiteAlsoStopped = true +param siteConfig = { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] +} +param slots = [ + { + basicPublishingCredentialsPolicies: [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + hybridConnectionRelays: [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } + ] + name: 'slot1' + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'sites-slot1' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + siteConfig: { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] + } + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } + { + basicPublishingCredentialsPolicies: [ + { + name: 'ftp' + } + { + name: 'scm' + } + ] + name: 'slot2' + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } +] +param storageAccountResourceId = '' +param storageAccountUseIdentityAuthentication = true +param vnetContentShareEnabled = true +param vnetImagePullEnabled = true +param vnetRouteAllEnabled = true +``` + +
+

+ ### Example 11: _Web App_ This instance deploys the module as Web App with the set of api management configuration. @@ -2020,7 +2818,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -2073,6 +2871,39 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswc001' +param serverFarmResourceId = '' +// Non-required parameters +param apiManagementConfiguration = { + id: '' +} +param appInsightResourceId = '' +param appSettingsKeyValuePairs = { + ENABLE_ORYX_BUILD: 'True' + SCM_DO_BUILD_DURING_DEPLOYMENT: 'False' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +param siteConfig = { + alwaysOn: true + appCommandLine: '' +} +``` + +
+

+ ### Example 12: _Windows Web App for Containers, using only defaults_ This instance deploys the module as a Windows based Container Web App with the minimum set of required parameters. @@ -2110,7 +2941,7 @@ module site 'br/public:avm/res/web/site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -2149,6 +2980,33 @@ module site 'br/public:avm/res/web/site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,container,windows' +param name = 'wswcamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +param siteConfig = { + appSettings: [ + { + name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' + value: 'false' + } + ] + windowsFxVersion: 'DOCKER|mcr.microsoft.com/azure-app-service/windows/parkingpage:latest' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/res/web/static-site/README.md b/avm/res/web/static-site/README.md index e77e8fe0c6..fda575fffb 100644 --- a/avm/res/web/static-site/README.md +++ b/avm/res/web/static-site/README.md @@ -62,7 +62,7 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,22 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/static-site:' + +// Required parameters +param name = 'wssmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -186,7 +202,7 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -308,6 +324,98 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/static-site:' + +// Required parameters +param name = 'wssmax001' +// Non-required parameters +param allowConfigFileUpdates = true +param appSettings = { + foo: 'bar' + setting: 1 +} +param enterpriseGradeCdnStatus = 'Disabled' +param functionAppSettings = { + foo: 'bar' + setting: 1 +} +param linkedBackend = { + resourceId: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'ba1328f0-c7ab-47bf-afbf-0637b9c02bbe' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Standard' +param stagingEnvironmentPolicy = '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. @@ -375,7 +483,7 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -458,6 +566,63 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/static-site:' + +// Required parameters +param name = 'wsswaf001' +// Non-required parameters +param allowConfigFileUpdates = true +param appSettings = { + foo: 'bar' + setting: 1 +} +param enterpriseGradeCdnStatus = 'Disabled' +param functionAppSettings = { + foo: 'bar' + setting: 1 +} +param linkedBackend = { + resourceId: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sku = 'Standard' +param stagingEnvironmentPolicy = 'Enabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 09355c6f9d..5d27ba34e7 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -1417,6 +1417,9 @@ function Set-UsageExamplesSection { [Parameter(Mandatory = $false)] [bool] $addBicep = $true, + [Parameter(Mandatory = $false)] + [bool] $addBicepParametersFile = $true, + [Parameter(Mandatory = $false)] [string] $SectionStartIdentifier = '## Usage examples' ) @@ -1591,20 +1594,30 @@ function Set-UsageExamplesSection { } } - # [5/6] Convert Bicep parameter block to JSON parameter block to enable processing + # [4/6] Convert Bicep parameter block to JSON parameter block to enable processing $conversionInputObject = @{ BicepParamBlock = ($paramsBlockArray | Out-String).TrimEnd() CurrentFilePath = $testFilePath } $paramsInJSONFormat = ConvertTo-FormattedJSONParameterObject @conversionInputObject - # [6/6] Convert JSON parameters back to Bicep and order & format them + # [5/6] Convert JSON parameters back to Bicep and order & format them $conversionInputObject = @{ JSONParameters = $paramsInJSONFormat RequiredParametersList = $RequiredParametersList } $bicepExample = ConvertTo-FormattedBicep @conversionInputObject + # [6/6] Convert the Bicep format to a Bicep parameters file format + $bicepParamBlockArray = $bicepExample -split '\r?\n' + $topLevelParamIndent = ([regex]::Match($bicepParamBlockArray[0], '^(\s+).*')).Captures.Groups[1].Value.Length + $bicepParametersFileExample = $bicepParamBlockArray | ForEach-Object { + $line = $_ + $line = $line -replace "^(\s{$topLevelParamIndent})([a-zA-Z]*)(:)(.*)", 'param $2 =$4' # Update any [ xyz: abc] to [param xyz = abc] + $line = $line -replace "^\s{$topLevelParamIndent}", '' # Update any [ xyz: abc] to [xyz: abc] + $line + } + # --------------------- # # Add Bicep example # # --------------------- # @@ -1652,7 +1665,7 @@ function Set-UsageExamplesSection { '', '

' '' - 'via JSON Parameter file' + 'via JSON parameters file' '' '```json', $orderedJSONExample.Trim() @@ -1662,6 +1675,33 @@ function Set-UsageExamplesSection { '

' ) } + + # ---------------------------------------- # + # Add Bicep parameters file example # + # ---------------------------------------- # + if ($addBicepParametersFile) { + + $formattedbicepParametersFileExample = @( + "using 'br/public:$($brLink):$($targetVersion)'" + '' + ) + $bicepParametersFileExample + + + # Build result + $testFilesContent += @( + '', + '

' + '' + 'via Bicep parameters file' + '' + '```bicep-params', + ($formattedbicepParametersFileExample | ForEach-Object { "$_" }).TrimEnd(), + '```', + '', + '
', + '

' + ) + } } else { # Non-module deployment (e.g., utility deployment) From 9510a282f91f45c2d40bebcaf0a83044c36a1fb7 Mon Sep 17 00:00:00 2001 From: Pankaj Agrawal Date: Mon, 7 Oct 2024 02:52:42 +0200 Subject: [PATCH 34/93] feat: support function app flex consumption plan (#3390) ## Description #3389 #3316 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.web.site](https://github.com/pankajagrawal16/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg?branch=feat%2F3389%2Fsupport-function-app-config)](https://github.com/pankajagrawal16/bicep-registry-modules/actions/workflows/avm.res.web.site.yml) [![avm.res.web.serverfarm](https://github.com/pankajagrawal16/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=feat%2F3389%2Fsupport-function-app-config)](https://github.com/pankajagrawal16/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/web/serverfarm/README.md | 1 + avm/res/web/serverfarm/main.bicep | 4 +- avm/res/web/serverfarm/main.json | 9 ++- avm/res/web/site/README.md | 10 ++- .../main.json | 4 +- .../web/site/config--appsettings/main.json | 4 +- .../web/site/config--authsettingsv2/main.json | 4 +- avm/res/web/site/config--logs/main.json | 4 +- avm/res/web/site/config--web/main.json | 4 +- .../web/site/extensions--msdeploy/main.json | 4 +- .../relay/main.json | 4 +- avm/res/web/site/main.bicep | 5 ++ avm/res/web/site/main.json | 81 ++++++++++++------- avm/res/web/site/slot/README.md | 10 ++- .../main.json | 4 +- .../site/slot/config--appsettings/main.json | 4 +- .../slot/config--authsettingsv2/main.json | 4 +- .../site/slot/extensions--msdeploy/main.json | 4 +- .../relay/main.json | 4 +- avm/res/web/site/slot/main.bicep | 6 +- avm/res/web/site/slot/main.json | 38 +++++---- avm/res/web/site/version.json | 4 +- 22 files changed, 136 insertions(+), 80 deletions(-) diff --git a/avm/res/web/serverfarm/README.md b/avm/res/web/serverfarm/README.md index 11fee06158..eb15593b7c 100644 --- a/avm/res/web/serverfarm/README.md +++ b/avm/res/web/serverfarm/README.md @@ -851,6 +851,7 @@ The name of the SKU will Determine the tier, size, family of the App Service Pla 'B1' 'P1v3' 'I1v2' + 'FC1' ``` ### Parameter: `tags` diff --git a/avm/res/web/serverfarm/main.bicep b/avm/res/web/serverfarm/main.bicep index a9dc015538..3d04b2f664 100644 --- a/avm/res/web/serverfarm/main.bicep +++ b/avm/res/web/serverfarm/main.bicep @@ -14,6 +14,7 @@ param name string 'B1' 'P1v3' 'I1v2' + 'FC1' ''' }) param skuName string = 'P1v3' @@ -129,7 +130,8 @@ resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = { tags: tags sku: { name: skuName - capacity: skuCapacity + capacity: skuName == 'FC1' ? null : skuCapacity + tier: skuName == 'FC1' ? 'FlexConsumption' : null } properties: { workerTierName: workerTierName diff --git a/avm/res/web/serverfarm/main.json b/avm/res/web/serverfarm/main.json index ba4108ee0b..e6d8dd5be3 100644 --- a/avm/res/web/serverfarm/main.json +++ b/avm/res/web/serverfarm/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.3.12046", - "templateHash": "12599229174633311842" + "version": "0.30.23.60470", + "templateHash": "489102920669919211" }, "name": "App Service Plan", "description": "This module deploys an App Service Plan.", @@ -205,7 +205,7 @@ "type": "string", "defaultValue": "P1v3", "metadata": { - "example": " 'F1'\n 'B1'\n 'P1v3'\n 'I1v2'\n ", + "example": " 'F1'\n 'B1'\n 'P1v3'\n 'I1v2'\n 'FC1'\n ", "description": "Optional. The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones." } }, @@ -379,7 +379,8 @@ "tags": "[parameters('tags')]", "sku": { "name": "[parameters('skuName')]", - "capacity": "[parameters('skuCapacity')]" + "capacity": "[if(equals(parameters('skuName'), 'FC1'), null(), parameters('skuCapacity'))]", + "tier": "[if(equals(parameters('skuName'), 'FC1'), 'FlexConsumption', null())]" }, "properties": { "workerTierName": "[parameters('workerTierName')]", diff --git a/avm/res/web/site/README.md b/avm/res/web/site/README.md index cbe8ec8fd9..449f709e49 100644 --- a/avm/res/web/site/README.md +++ b/avm/res/web/site/README.md @@ -27,7 +27,7 @@ This module deploys a Web or Function App. | `Microsoft.Web/sites/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/extensions` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/extensions) | | `Microsoft.Web/sites/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/hybridConnectionNamespaces/relays) | -| `Microsoft.Web/sites/slots` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots) | +| `Microsoft.Web/sites/slots` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/slots) | | `Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots/hybridConnectionNamespaces/relays) | @@ -3037,6 +3037,7 @@ param siteConfig = { | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`enabled`](#parameter-enabled) | bool | Setting this value to false disables the app (takes the app offline). | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`functionAppConfig`](#parameter-functionappconfig) | object | The Function App configuration object. | | [`hostNameSslStates`](#parameter-hostnamesslstates) | array | Hostname SSL states are used to manage the SSL bindings for app's hostnames. | | [`httpsOnly`](#parameter-httpsonly) | bool | Configures a site to accept only HTTPS requests. Issues redirect for HTTP requests. | | [`hybridConnectionRelays`](#parameter-hybridconnectionrelays) | array | Names of hybrid connection relays to connect app with. | @@ -3366,6 +3367,13 @@ Enable/Disable usage telemetry for module. - Type: bool - Default: `True` +### Parameter: `functionAppConfig` + +The Function App configuration object. + +- Required: No +- Type: object + ### Parameter: `hostNameSslStates` Hostname SSL states are used to manage the SSL bindings for app's hostnames. diff --git a/avm/res/web/site/basic-publishing-credentials-policy/main.json b/avm/res/web/site/basic-publishing-credentials-policy/main.json index a2c95fcbcd..2f34f50dae 100644 --- a/avm/res/web/site/basic-publishing-credentials-policy/main.json +++ b/avm/res/web/site/basic-publishing-credentials-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5861139703409371797" + "version": "0.30.23.60470", + "templateHash": "2961784489694025029" }, "name": "Web Site Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Basic Publishing Credentials Policy.", diff --git a/avm/res/web/site/config--appsettings/main.json b/avm/res/web/site/config--appsettings/main.json index c50105f501..0a244e922c 100644 --- a/avm/res/web/site/config--appsettings/main.json +++ b/avm/res/web/site/config--appsettings/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3998275265127709875" + "version": "0.30.23.60470", + "templateHash": "10845600494881775271" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting.", diff --git a/avm/res/web/site/config--authsettingsv2/main.json b/avm/res/web/site/config--authsettingsv2/main.json index 88d23811d2..40a2f7b4a3 100644 --- a/avm/res/web/site/config--authsettingsv2/main.json +++ b/avm/res/web/site/config--authsettingsv2/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15126303852151434516" + "version": "0.30.23.60470", + "templateHash": "9901606105705730734" }, "name": "Site Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", diff --git a/avm/res/web/site/config--logs/main.json b/avm/res/web/site/config--logs/main.json index a26a2fc11e..df3ade39ea 100644 --- a/avm/res/web/site/config--logs/main.json +++ b/avm/res/web/site/config--logs/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1719886395722436280" + "version": "0.30.23.60470", + "templateHash": "5314244939846396394" }, "name": "Site logs Config", "description": "This module deploys a Site logs Configuration.", diff --git a/avm/res/web/site/config--web/main.json b/avm/res/web/site/config--web/main.json index 3a995656e4..7e101b4952 100644 --- a/avm/res/web/site/config--web/main.json +++ b/avm/res/web/site/config--web/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7195763436259190781" + "version": "0.30.23.60470", + "templateHash": "4796843420829841335" }, "name": "Site Api Management Config", "description": "This module deploys a Site Api Management Configuration.", diff --git a/avm/res/web/site/extensions--msdeploy/main.json b/avm/res/web/site/extensions--msdeploy/main.json index fdc1b30f96..79be0b21b8 100644 --- a/avm/res/web/site/extensions--msdeploy/main.json +++ b/avm/res/web/site/extensions--msdeploy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", diff --git a/avm/res/web/site/hybrid-connection-namespace/relay/main.json b/avm/res/web/site/hybrid-connection-namespace/relay/main.json index c0dd469939..6f55127261 100644 --- a/avm/res/web/site/hybrid-connection-namespace/relay/main.json +++ b/avm/res/web/site/hybrid-connection-namespace/relay/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7661794789768148013" + "version": "0.30.23.60470", + "templateHash": "1833159536134902561" }, "name": "Web/Function Apps Hybrid Connection Relay", "description": "This module deploys a Site Hybrid Connection Namespace Relay.", diff --git a/avm/res/web/site/main.bicep b/avm/res/web/site/main.bicep index cbd5824ec5..369399a325 100644 --- a/avm/res/web/site/main.bicep +++ b/avm/res/web/site/main.bicep @@ -69,6 +69,9 @@ param siteConfig object = { alwaysOn: true } +@description('Optional. The Function App configuration object.') +param functionAppConfig object? + @description('Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions.') param storageAccountResourceId string? @@ -265,6 +268,7 @@ resource app 'Microsoft.Web/sites@2023-12-01' = { keyVaultReferenceIdentity: keyVaultAccessIdentityResourceId virtualNetworkSubnetId: virtualNetworkSubnetId siteConfig: siteConfig + functionAppConfig: functionAppConfig clientCertEnabled: clientCertEnabled clientCertExclusionPaths: clientCertExclusionPaths clientCertMode: clientCertMode @@ -352,6 +356,7 @@ module app_slots 'slot/main.bicep' = [ storageAccountRequired: slot.?storageAccountRequired ?? storageAccountRequired virtualNetworkSubnetId: slot.?virtualNetworkSubnetId ?? virtualNetworkSubnetId siteConfig: slot.?siteConfig ?? siteConfig + functionAppConfig: slot.?functionAppConfig ?? functionAppConfig storageAccountResourceId: slot.?storageAccountResourceId ?? storageAccountResourceId storageAccountUseIdentityAuthentication: slot.?storageAccountUseIdentityAuthentication ?? storageAccountUseIdentityAuthentication appInsightResourceId: slot.?appInsightResourceId ?? appInsightResourceId diff --git a/avm/res/web/site/main.json b/avm/res/web/site/main.json index d3577e551f..ad24381ffc 100644 --- a/avm/res/web/site/main.json +++ b/avm/res/web/site/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4626438010490721609" + "version": "0.30.23.60470", + "templateHash": "12115053115954215642" }, "name": "Web/Function Apps", "description": "This module deploys a Web or Function App.", @@ -607,6 +607,13 @@ "description": "Optional. The site config object." } }, + "functionAppConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Function App configuration object." + } + }, "storageAccountResourceId": { "type": "string", "nullable": true, @@ -876,6 +883,7 @@ "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", "siteConfig": "[parameters('siteConfig')]", + "functionAppConfig": "[parameters('functionAppConfig')]", "clientCertEnabled": "[parameters('clientCertEnabled')]", "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", "clientCertMode": "[parameters('clientCertMode')]", @@ -1008,8 +1016,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3998275265127709875" + "version": "0.30.23.60470", + "templateHash": "10845600494881775271" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting.", @@ -1172,8 +1180,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15126303852151434516" + "version": "0.30.23.60470", + "templateHash": "9901606105705730734" }, "name": "Site Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", @@ -1276,8 +1284,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1719886395722436280" + "version": "0.30.23.60470", + "templateHash": "5314244939846396394" }, "name": "Site logs Config", "description": "This module deploys a Site logs Configuration.", @@ -1371,8 +1379,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7195763436259190781" + "version": "0.30.23.60470", + "templateHash": "4796843420829841335" }, "name": "Site Api Management Config", "description": "This module deploys a Site Api Management Configuration.", @@ -1465,8 +1473,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", @@ -1589,6 +1597,9 @@ "siteConfig": { "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'siteConfig'), parameters('siteConfig'))]" }, + "functionAppConfig": { + "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'functionAppConfig'), parameters('functionAppConfig'))]" + }, "storageAccountResourceId": { "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'storageAccountResourceId'), parameters('storageAccountResourceId'))]" }, @@ -1684,8 +1695,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13282951347078727812" + "version": "0.30.23.60470", + "templateHash": "16398712095816733590" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -2258,6 +2269,13 @@ "description": "Optional. The site config object." } }, + "functionAppConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Function App config object." + } + }, "storageAccountResourceId": { "type": "string", "nullable": true, @@ -2504,7 +2522,7 @@ }, "slot": { "type": "Microsoft.Web/sites/slots", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), parameters('name'))]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -2519,6 +2537,7 @@ "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", "siteConfig": "[parameters('siteConfig')]", + "functionAppConfig": "[parameters('functionAppConfig')]", "clientCertEnabled": "[parameters('clientCertEnabled')]", "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", "clientCertMode": "[parameters('clientCertMode')]", @@ -2657,8 +2676,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9363357518124041583" + "version": "0.30.23.60470", + "templateHash": "4751023237415156564" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -2840,8 +2859,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3412962465179136371" + "version": "0.30.23.60470", + "templateHash": "12145671704242923554" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", @@ -2962,8 +2981,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6875784212879192632" + "version": "0.30.23.60470", + "templateHash": "9837227282603977030" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", @@ -3088,8 +3107,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4120073340411344208" + "version": "0.30.23.60470", + "templateHash": "1330320751784094185" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", @@ -3194,8 +3213,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", @@ -4058,14 +4077,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('slot', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('slot', '2023-12-01', 'full'), 'identity'), 'principalId'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('slot', '2022-09-01', 'full').location]" + "value": "[reference('slot', '2023-12-01', 'full').location]" }, "privateEndpoints": { "type": "array", @@ -4123,8 +4142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5861139703409371797" + "version": "0.30.23.60470", + "templateHash": "2961784489694025029" }, "name": "Web Site Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Basic Publishing Credentials Policy.", @@ -4239,8 +4258,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7661794789768148013" + "version": "0.30.23.60470", + "templateHash": "1833159536134902561" }, "name": "Web/Function Apps Hybrid Connection Relay", "description": "This module deploys a Site Hybrid Connection Namespace Relay.", diff --git a/avm/res/web/site/slot/README.md b/avm/res/web/site/slot/README.md index 135fa084b8..60d39f4ef0 100644 --- a/avm/res/web/site/slot/README.md +++ b/avm/res/web/site/slot/README.md @@ -21,7 +21,7 @@ This module deploys a Web or Function App Deployment Slot. | `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.Web/sites/extensions` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/extensions) | -| `Microsoft.Web/sites/slots` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots) | +| `Microsoft.Web/sites/slots` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/slots) | | `Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots/hybridConnectionNamespaces/relays) | @@ -61,6 +61,7 @@ This module deploys a Web or Function App Deployment Slot. | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`enabled`](#parameter-enabled) | bool | Setting this value to false disables the app (takes the app offline). | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`functionAppConfig`](#parameter-functionappconfig) | object | The Function App config object. | | [`hostNameSslStates`](#parameter-hostnamesslstates) | array | Hostname SSL states are used to manage the SSL bindings for app's hostnames. | | [`httpsOnly`](#parameter-httpsonly) | bool | Configures a slot to accept only HTTPS requests. Issues redirect for HTTP requests. | | [`hybridConnectionRelays`](#parameter-hybridconnectionrelays) | array | Names of hybrid connection relays to connect app with. | @@ -387,6 +388,13 @@ Enable/Disable usage telemetry for module. - Type: bool - Default: `True` +### Parameter: `functionAppConfig` + +The Function App config object. + +- Required: No +- Type: object + ### Parameter: `hostNameSslStates` Hostname SSL states are used to manage the SSL bindings for app's hostnames. diff --git a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json index 93bbb33ac2..f5534dba2f 100644 --- a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json +++ b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6875784212879192632" + "version": "0.30.23.60470", + "templateHash": "9837227282603977030" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", diff --git a/avm/res/web/site/slot/config--appsettings/main.json b/avm/res/web/site/slot/config--appsettings/main.json index af2de6024a..db3ee7ad32 100644 --- a/avm/res/web/site/slot/config--appsettings/main.json +++ b/avm/res/web/site/slot/config--appsettings/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9363357518124041583" + "version": "0.30.23.60470", + "templateHash": "4751023237415156564" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", diff --git a/avm/res/web/site/slot/config--authsettingsv2/main.json b/avm/res/web/site/slot/config--authsettingsv2/main.json index 489aa559b3..65b5d4fa2b 100644 --- a/avm/res/web/site/slot/config--authsettingsv2/main.json +++ b/avm/res/web/site/slot/config--authsettingsv2/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3412962465179136371" + "version": "0.30.23.60470", + "templateHash": "12145671704242923554" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", diff --git a/avm/res/web/site/slot/extensions--msdeploy/main.json b/avm/res/web/site/slot/extensions--msdeploy/main.json index fdc1b30f96..79be0b21b8 100644 --- a/avm/res/web/site/slot/extensions--msdeploy/main.json +++ b/avm/res/web/site/slot/extensions--msdeploy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", diff --git a/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json b/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json index fb8ad95a8d..8fd1b8a2bb 100644 --- a/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json +++ b/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4120073340411344208" + "version": "0.30.23.60470", + "templateHash": "1330320751784094185" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", diff --git a/avm/res/web/site/slot/main.bicep b/avm/res/web/site/slot/main.bicep index 95b2e0eff7..266ea3d893 100644 --- a/avm/res/web/site/slot/main.bicep +++ b/avm/res/web/site/slot/main.bicep @@ -57,6 +57,9 @@ param siteConfig object = { alwaysOn: true } +@description('Optional. The Function App config object.') +param functionAppConfig object? + @description('Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions.') param storageAccountResourceId string? @@ -216,7 +219,7 @@ resource app 'Microsoft.Web/sites@2021-03-01' existing = { name: appName } -resource slot 'Microsoft.Web/sites/slots@2022-09-01' = { +resource slot 'Microsoft.Web/sites/slots@2023-12-01' = { name: name parent: app location: location @@ -236,6 +239,7 @@ resource slot 'Microsoft.Web/sites/slots@2022-09-01' = { keyVaultReferenceIdentity: keyVaultAccessIdentityResourceId virtualNetworkSubnetId: virtualNetworkSubnetId siteConfig: siteConfig + functionAppConfig: functionAppConfig clientCertEnabled: clientCertEnabled clientCertExclusionPaths: clientCertExclusionPaths clientCertMode: clientCertMode diff --git a/avm/res/web/site/slot/main.json b/avm/res/web/site/slot/main.json index 3120546cad..ede1b02e37 100644 --- a/avm/res/web/site/slot/main.json +++ b/avm/res/web/site/slot/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13282951347078727812" + "version": "0.30.23.60470", + "templateHash": "16398712095816733590" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -579,6 +579,13 @@ "description": "Optional. The site config object." } }, + "functionAppConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Function App config object." + } + }, "storageAccountResourceId": { "type": "string", "nullable": true, @@ -825,7 +832,7 @@ }, "slot": { "type": "Microsoft.Web/sites/slots", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), parameters('name'))]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -840,6 +847,7 @@ "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", "siteConfig": "[parameters('siteConfig')]", + "functionAppConfig": "[parameters('functionAppConfig')]", "clientCertEnabled": "[parameters('clientCertEnabled')]", "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", "clientCertMode": "[parameters('clientCertMode')]", @@ -978,8 +986,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9363357518124041583" + "version": "0.30.23.60470", + "templateHash": "4751023237415156564" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -1161,8 +1169,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3412962465179136371" + "version": "0.30.23.60470", + "templateHash": "12145671704242923554" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", @@ -1283,8 +1291,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6875784212879192632" + "version": "0.30.23.60470", + "templateHash": "9837227282603977030" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", @@ -1409,8 +1417,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4120073340411344208" + "version": "0.30.23.60470", + "templateHash": "1330320751784094185" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", @@ -1515,8 +1523,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", @@ -2379,14 +2387,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('slot', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('slot', '2023-12-01', 'full'), 'identity'), 'principalId'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('slot', '2022-09-01', 'full').location]" + "value": "[reference('slot', '2023-12-01', 'full').location]" }, "privateEndpoints": { "type": "array", diff --git a/avm/res/web/site/version.json b/avm/res/web/site/version.json index b8b30a0125..bb03e3a03d 100644 --- a/avm/res/web/site/version.json +++ b/avm/res/web/site/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.9", + "version": "0.10", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} From 176966466f75b149c4f520888851d457ee1eb94d Mon Sep 17 00:00:00 2001 From: Marcin Gastol <62604769+marcingastol@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:11:22 +0000 Subject: [PATCH 35/93] fix: InvalidKeyRotationPolicy (#3381) ## Description ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/marcingastol/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg)](https://github.com/marcingastol/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ X] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ X] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ X] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ X] Update to documentation ## Checklist - [ X] I'm sure there are no other open Pull Requests for the same update/change - [ X] I have run `Set-AVMModule` locally to generate the supporting module files. - [ X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Microsoft Learn Student Co-authored-by: Felix Borst <17405838+fblix@users.noreply.github.com> --- avm/res/key-vault/vault/key/main.bicep | 4 +++- avm/res/key-vault/vault/key/main.json | 18 +++------------- avm/res/key-vault/vault/main.json | 30 ++++++++------------------ avm/res/key-vault/vault/version.json | 2 +- 4 files changed, 16 insertions(+), 38 deletions(-) diff --git a/avm/res/key-vault/vault/key/main.bicep b/avm/res/key-vault/vault/key/main.bicep index 45e00bf511..5f54bc9464 100644 --- a/avm/res/key-vault/vault/key/main.bicep +++ b/avm/res/key-vault/vault/key/main.bicep @@ -129,8 +129,10 @@ resource key 'Microsoft.KeyVault/vaults/keys@2022-07-01' = { keyOps: keyOps keySize: keySize kty: kty - rotationPolicy: rotationPolicy ?? {} release_policy: releasePolicy ?? {} + ...(empty(rotationPolicy) ? {} : { + rotationPolicy: rotationPolicy + }) } } diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 63c2159cb2..6976827555 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14269695922191217406" + "version": "0.30.3.12046", + "templateHash": "13039550242026782790" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -232,19 +232,7 @@ "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())]" - }, + "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(empty(parameters('rotationPolicy')), createObject(), createObject('rotationPolicy', parameters('rotationPolicy')))))]", "dependsOn": [ "keyVault" ] diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 74ea3bdd03..a6769b9cb6 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8938543730613882040" + "version": "0.30.23.60470", + "templateHash": "4499855760252174192" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -1224,8 +1224,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7494731697751039419" + "version": "0.30.23.60470", + "templateHash": "15469258025112973480" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -1493,8 +1493,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "114626909766354577" + "version": "0.30.23.60470", + "templateHash": "10121697157844029321" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1791,8 +1791,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14269695922191217406" + "version": "0.30.23.60470", + "templateHash": "796741209006922272" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -2018,19 +2018,7 @@ "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())]" - }, + "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(empty(parameters('rotationPolicy')), createObject(), createObject('rotationPolicy', parameters('rotationPolicy')))))]", "dependsOn": [ "keyVault" ] diff --git a/avm/res/key-vault/vault/version.json b/avm/res/key-vault/vault/version.json index b8b30a0125..9c08aae215 100644 --- a/avm/res/key-vault/vault/version.json +++ b/avm/res/key-vault/vault/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.9", + "version": "0.10", "pathFilters": [ "./main.json" ] From 0e259f52a4e1f0a18277af3fcfe9ab236d882caa Mon Sep 17 00:00:00 2001 From: Chinedum Echeta <60179183+cecheta@users.noreply.github.com> Date: Mon, 7 Oct 2024 05:22:07 -0700 Subject: [PATCH 36/93] fix: `avm/res/machine-learning-services/workspace` Add correct permissions for CI (#3445) ## Description * Adds missing permission for failing `avm/res/machine-learning-service/workspace` module * Adds `scope` to permission in `avm/ptn/ai-platform/baseline` module ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.machine-learning-services.workspace](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml/badge.svg?branch=permissions)](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml) | | [![avm.ptn.ai-platform.baseline](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml/badge.svg?branch=permissions)](https://github.com/cecheta/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [x] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- .../tests/e2e/waf-aligned/dependencies.bicep | 1 + .../workspace/compute/main.json | 4 +- .../workspace/connection/main.json | 4 +- .../workspace/main.json | 12 +++--- .../tests/e2e/encr/dependencies.bicep | 37 ++++++++++++++++--- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep index fbb0fe92d4..cf931cdcdf 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep @@ -26,6 +26,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid(resourceGroup().id, storageAccount.id, managedIdentity.id) + scope: storageAccount properties: { roleDefinitionId: subscriptionResourceId( 'Microsoft.Authorization/roleDefinitions', diff --git a/avm/res/machine-learning-services/workspace/compute/main.json b/avm/res/machine-learning-services/workspace/compute/main.json index 24fa048bd0..c3832c8377 100644 --- a/avm/res/machine-learning-services/workspace/compute/main.json +++ b/avm/res/machine-learning-services/workspace/compute/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8580750401363518569" + "version": "0.30.23.60470", + "templateHash": "6461308246344228681" }, "name": "Machine Learning Services Workspaces Computes", "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", diff --git a/avm/res/machine-learning-services/workspace/connection/main.json b/avm/res/machine-learning-services/workspace/connection/main.json index 6e49f757aa..f4efdf611d 100644 --- a/avm/res/machine-learning-services/workspace/connection/main.json +++ b/avm/res/machine-learning-services/workspace/connection/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2277907099827503661" + "version": "0.30.23.60470", + "templateHash": "11897886685116125832" }, "name": "Machine Learning Services Workspaces Connections", "description": "This module creates a connection in a Machine Learning Services workspace.", diff --git a/avm/res/machine-learning-services/workspace/main.json b/avm/res/machine-learning-services/workspace/main.json index c90b0b9598..188ff7e44c 100644 --- a/avm/res/machine-learning-services/workspace/main.json +++ b/avm/res/machine-learning-services/workspace/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6210663004291725942" + "version": "0.30.23.60470", + "templateHash": "13428062064493278756" }, "name": "Machine Learning Services Workspaces", "description": "This module deploys a Machine Learning Services Workspace.", @@ -1981,8 +1981,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8580750401363518569" + "version": "0.30.23.60470", + "templateHash": "6461308246344228681" }, "name": "Machine Learning Services Workspaces Computes", "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", @@ -2244,8 +2244,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2277907099827503661" + "version": "0.30.23.60470", + "templateHash": "11897886685116125832" }, "name": "Machine Learning Services Workspaces Connections", "description": "This module creates a connection in a Machine Learning Services workspace.", diff --git a/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep b/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep index 7a7181129f..946aaa8d9a 100644 --- a/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep +++ b/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep @@ -61,15 +61,42 @@ resource keyVaultServicePermissions 'Microsoft.Authorization/roleAssignments@202 principalType: 'ServicePrincipal' } } -resource keyVaultDataPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-KeyVault-Data-Admin-RoleAssignment') - scope: keyVault::key + +resource keyVaultAdminPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-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 keyVaultUserPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-KeyVault-Crypto-User-RoleAssignment') + scope: keyVault + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e147488a-f6f5-4113-8e2d-b22465e65bf6' + ) // Key Vault Crypto Service Encryption User + principalType: 'ServicePrincipal' + } +} + +resource storageAccountPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${secondaryStorageAccount.id}-${location}-${managedIdentity.id}-StorageAccount-RoleAssignment') + scope: secondaryStorageAccount properties: { principalId: managedIdentity.properties.principalId roleDefinitionId: subscriptionResourceId( 'Microsoft.Authorization/roleDefinitions', - '12338af0-0e69-4776-bea7-57ae8d297424' - ) // Key Vault Crypto User + 'b556d68e-0be0-4f35-a333-ad7ee1ce17ea' + ) // Azure AI Enterprise Network Connection Approver principalType: 'ServicePrincipal' } } From f8eb83255005e28bf0fa5cdc42af03fa4fdbb77c Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 7 Oct 2024 21:37:07 +0200 Subject: [PATCH 37/93] feat: Updated Virtual-Machine-Images AVM module references (#3444) ## Description - Updated Virtual-Machine-Images AVM module references ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.virtual-machine-images.azure-image-builder](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml/badge.svg?branch=users%2Falsehr%2FimageParameters&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- .../azure-image-builder/README.md | 107 +- .../azure-image-builder/main.bicep | 43 +- .../azure-image-builder/main.json | 1566 ++++++++++++----- .../tests/e2e/defaults/main.test.bicep | 9 +- .../tests/e2e/deployAll/main.test.bicep | 9 +- .../dependencies.bicep | 36 +- .../tests/e2e/deployOnlyBase/main.test.bicep | 9 +- .../e2e/deployOnlyImage/dependencies.bicep | 38 +- 8 files changed, 1254 insertions(+), 563 deletions(-) diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/README.md b/avm/ptn/virtual-machine-images/azure-image-builder/README.md index a161d38594..0ddfb123e2 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/README.md +++ b/avm/ptn/virtual-machine-images/azure-image-builder/README.md @@ -18,17 +18,17 @@ This module provides you with a packaged solution to create custom images using | :-- | :-- | | `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` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries) | +| `Microsoft.Compute/galleries` | [2023-07-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-03/galleries) | | `Microsoft.Compute/galleries/applications` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/applications) | -| `Microsoft.Compute/galleries/images` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/images) | +| `Microsoft.Compute/galleries/images` | [2023-07-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-03/galleries/images) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | | `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) | | `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | -| `Microsoft.Network/virtualNetworks` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks) | -| `Microsoft.Network/virtualNetworks/subnets` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks/subnets) | -| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworks/virtualNetworkPeerings) | +| `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | +| `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/virtualNetworkPeerings) | | `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2023-08-01/deploymentScripts) | | `Microsoft.Resources/resourceGroups` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2024-03-01/resourceGroups) | | `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts) | @@ -77,11 +77,14 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b computeGalleryImageDefinitions: [ { hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } name: 'sid-linux' - offer: 'devops_linux' + osState: 'Generalized' osType: 'Linux' - publisher: 'devops' - sku: 'devops_linux_az' } ] computeGalleryName: 'galapvmiaibmin' @@ -121,11 +124,14 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b "value": [ { "hyperVGeneration": "V2", + "identifier": { + "offer": "devops_linux", + "publisher": "devops", + "sku": "devops_linux_az" + }, "name": "sid-linux", - "offer": "devops_linux", - "osType": "Linux", - "publisher": "devops", - "sku": "devops_linux_az" + "osState": "Generalized", + "osType": "Linux" } ] }, @@ -173,11 +179,14 @@ param computeGalleryImageDefinitionName = '' param computeGalleryImageDefinitions = [ { hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } name: 'sid-linux' - offer: 'devops_linux' + osState: 'Generalized' osType: 'Linux' - publisher: 'devops' - sku: 'devops_linux_az' } ] param computeGalleryName = 'galapvmiaibmin' @@ -216,11 +225,14 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b computeGalleryImageDefinitions: [ { hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } name: '' - offer: 'devops_linux' + osState: 'Generalized' osType: 'Linux' - publisher: 'devops' - sku: 'devops_linux_az' } ] computeGalleryName: 'galapvmiaiba' @@ -291,11 +303,14 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b "value": [ { "hyperVGeneration": "V2", + "identifier": { + "offer": "devops_linux", + "publisher": "devops", + "sku": "devops_linux_az" + }, "name": "", - "offer": "devops_linux", - "osType": "Linux", - "publisher": "devops", - "sku": "devops_linux_az" + "osState": "Generalized", + "osType": "Linux" } ] }, @@ -380,11 +395,14 @@ param computeGalleryImageDefinitionName = '' param computeGalleryImageDefinitions = [ { hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } name: '' - offer: 'devops_linux' + osState: 'Generalized' osType: 'Linux' - publisher: 'devops' - sku: 'devops_linux_az' } ] param computeGalleryName = 'galapvmiaiba' @@ -649,11 +667,14 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b computeGalleryImageDefinitions: [ { hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } name: '' - offer: 'devops_linux' + osState: 'Generalized' osType: 'Linux' - publisher: 'devops' - sku: 'devops_linux_az' } ] computeGalleryName: 'galapvmiaibob' @@ -694,11 +715,14 @@ module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-b "value": [ { "hyperVGeneration": "V2", + "identifier": { + "offer": "devops_linux", + "publisher": "devops", + "sku": "devops_linux_az" + }, "name": "", - "offer": "devops_linux", - "osType": "Linux", - "publisher": "devops", - "sku": "devops_linux_az" + "osState": "Generalized", + "osType": "Linux" } ] }, @@ -749,11 +773,14 @@ param computeGalleryImageDefinitionName = '' param computeGalleryImageDefinitions = [ { hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } name: '' - offer: 'devops_linux' + osState: 'Generalized' osType: 'Linux' - publisher: 'devops' - sku: 'devops_linux_az' } ] param computeGalleryName = 'galapvmiaibob' @@ -1259,12 +1286,12 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/compute/gallery:0.4.0` | Remote reference | -| `br/public:avm/res/managed-identity/user-assigned-identity:0.2.2` | Remote reference | -| `br/public:avm/res/network/virtual-network:0.1.6` | Remote reference | -| `br/public:avm/res/resources/deployment-script:0.3.1` | Remote reference | +| `br/public:avm/res/compute/gallery:0.7.0` | Remote reference | +| `br/public:avm/res/managed-identity/user-assigned-identity:0.4.0` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | +| `br/public:avm/res/resources/deployment-script:0.4.0` | Remote reference | | `br/public:avm/res/storage/storage-account:0.9.1` | Remote reference | -| `br/public:avm/res/virtual-machine-images/image-template:0.3.1` | Remote reference | +| `br/public:avm/res/virtual-machine-images/image-template:0.4.0` | Remote reference | ## Notes diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/main.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/main.bicep index 41c05593b8..34d5a6048e 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/main.bicep +++ b/avm/ptn/virtual-machine-images/azure-image-builder/main.bicep @@ -164,7 +164,7 @@ resource imageTemplateRg 'Microsoft.Resources/resourceGroups@2024-03-01' = if (d } // User Assigned Identity (MSI) -module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { +module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { name: '${deployment().name}-ds-msi' scope: rg params: { @@ -174,7 +174,7 @@ module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = } } -module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { +module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { name: '${deployment().name}-image-msi' scope: rg params: { @@ -186,7 +186,6 @@ module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2 // MSI Subscription contributor assignment resource imageMSI_rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { - // name: guid(subscription().subscriptionId, imageManagedIdentityName, contributorRole.id) name: guid( subscription().id, '${subscription().id}/resourceGroups/${resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/${imageManagedIdentityName}', @@ -203,7 +202,7 @@ resource imageMSI_rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = if } // Azure Compute Gallery -module azureComputeGallery 'br/public:avm/res/compute/gallery:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { +module azureComputeGallery 'br/public:avm/res/compute/gallery:0.7.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { name: '${deployment().name}-acg' scope: rg params: { @@ -215,7 +214,7 @@ module azureComputeGallery 'br/public:avm/res/compute/gallery:0.4.0' = if (deplo } // Image Template Virtual Network -module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { +module vnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { name: '${deployment().name}-vnet' scope: rg params: { @@ -229,9 +228,7 @@ module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = if (deploymentsT addressPrefix: virtualNetworkSubnetAddressPrefix privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } + 'Microsoft.Storage' ] } { @@ -239,18 +236,9 @@ module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = if (deploymentsT addressPrefix: virtualNetworkDeploymentScriptSubnetAddressPrefix privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET - temp serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } - ] - delegations: [ - { - name: 'Microsoft.ContainerInstance.containerGroups' - properties: { - serviceName: 'Microsoft.ContainerInstance/containerGroups' - } - } + 'Microsoft.Storage' ] + delegation: 'Microsoft.ContainerInstance/containerGroups' } ] location: location @@ -363,7 +351,7 @@ module dsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = if ( // ============================== // // Upload storage account files -module storageAccount_upload 'br/public:avm/res/resources/deployment-script:0.3.1' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base' || deploymentsToPerform == 'Only assets & image') { +module storageAccount_upload 'br/public:avm/res/resources/deployment-script:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base' || deploymentsToPerform == 'Only assets & image') { name: '${deployment().name}-storage-upload-ds' scope: resourceGroup(resourceGroupName) params: { @@ -382,13 +370,6 @@ module storageAccount_upload 'br/public:avm/res/resources/deployment-script:0.3. ] } scriptContent: loadTextContent('../../../utilities/e2e-template-assets/scripts/Set-StorageContainerContentByEnvVar.ps1') - // environmentVariables: [ - // map(range(0, length(storageAccountFilesToUpload ?? [])), index => { - // name: '__SCRIPT__${storageAccountFilesToUpload![index].name}' - // value: storageAccountFilesToUpload![index].?value - // secureValue: storageAccountFilesToUpload![index].?secureValue - // }) - // ] environmentVariables: map(storageAccountFilesToUpload ?? [], file => { name: '__SCRIPT__${replace(replace(file.name, '-', '__'), '.', '_') }' // May only be alphanumeric characters & underscores. The upload will replace '_' with '.' and '__' with '-'. E.g., Install__LinuxPowerShell_sh will be Install-LinuxPowerShell.sh value: file.?value @@ -438,7 +419,7 @@ resource dsMsi_existing 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-0 scope: resourceGroup(resourceGroupName) } -module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:0.3.1' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') { +module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') { name: '${deployment().name}-it' scope: resourceGroup(resourceGroupName) params: { @@ -501,7 +482,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:0. } // Deployment script to trigger image build -module imageTemplate_trigger 'br/public:avm/res/resources/deployment-script:0.3.1' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') { +module imageTemplate_trigger 'br/public:avm/res/resources/deployment-script:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') { name: '${deployment().name}-imageTemplate-trigger-ds' scope: resourceGroup(resourceGroupName) params: { @@ -555,7 +536,7 @@ module imageTemplate_trigger 'br/public:avm/res/resources/deployment-script:0.3. ] } -module imageTemplate_wait 'br/public:avm/res/resources/deployment-script:0.3.1' = if (waitForImageBuild && (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image')) { +module imageTemplate_wait 'br/public:avm/res/resources/deployment-script:0.4.0' = if (waitForImageBuild && (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image')) { name: '${deployment().name}-imageTemplate-wait-ds' scope: resourceGroup(resourceGroupName) params: { @@ -611,7 +592,7 @@ module imageTemplate_wait 'br/public:avm/res/resources/deployment-script:0.3.1' // =============== // // Definitions // // =============== // - +@export() type storageAccountFilesToUploadType = { @description('Required. The name of the environment variable.') name: string diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/main.json b/avm/ptn/virtual-machine-images/azure-image-builder/main.json index 408049bed0..e8e8b71562 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/main.json +++ b/avm/ptn/virtual-machine-images/azure-image-builder/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12788075391199236027" + "version": "0.30.23.60470", + "templateHash": "4580919221810730076" }, "name": "Custom Images using Azure Image Builder", "description": "This module provides you with a packaged solution to create custom images using the Azure Image Builder service publishing to an Azure Compute Gallery.", @@ -36,6 +36,9 @@ "description": "Required. The value of the environment variable." } } + }, + "metadata": { + "__bicep_export!": true } } }, @@ -357,8 +360,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "8316967256052237432" + "version": "0.29.47.4906", + "templateHash": "10609859695208799167" }, "name": "User Assigned Identities", "description": "This module deploys a User Assigned Identity.", @@ -395,6 +398,13 @@ "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": { @@ -541,13 +551,20 @@ } }, "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -556,7 +573,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.2.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -596,20 +613,20 @@ "userAssignedIdentity_roleAssignments": { "copy": { "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), 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)]", + "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": "[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')]" + "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" @@ -653,8 +670,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "663270811232806628" + "version": "0.29.47.4906", + "templateHash": "3716898257490923786" }, "name": "User Assigned Identity Federated Identity Credential", "description": "This module deploys a User Assigned Identity Federated Identity Credential.", @@ -813,8 +830,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "8316967256052237432" + "version": "0.29.47.4906", + "templateHash": "10609859695208799167" }, "name": "User Assigned Identities", "description": "This module deploys a User Assigned Identity.", @@ -851,6 +868,13 @@ "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": { @@ -997,13 +1021,20 @@ } }, "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -1012,7 +1043,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.2.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1052,20 +1083,20 @@ "userAssignedIdentity_roleAssignments": { "copy": { "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), 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)]", + "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": "[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')]" + "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" @@ -1109,8 +1140,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "663270811232806628" + "version": "0.29.47.4906", + "templateHash": "3716898257490923786" }, "name": "User Assigned Identity Federated Identity Credential", "description": "This module deploys a User Assigned Identity Federated Identity Credential.", @@ -1272,8 +1303,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "9752194366887174506" + "version": "0.29.47.4906", + "templateHash": "3415776249412580608" }, "name": "Azure Compute Galleries", "description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).", @@ -1302,14 +1333,20 @@ "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": { @@ -1368,8 +1405,243 @@ } } } + } + }, + "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." + } + }, + "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" + ], + "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. Specifiy if the image supports hibernation." + } + }, + "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." + } + } + } + }, + "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." + } + } }, - "nullable": true + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "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" + } + } } }, "parameters": { @@ -1387,6 +1659,13 @@ "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, @@ -1403,6 +1682,9 @@ }, "images": { "type": "array", + "items": { + "$ref": "#/definitions/imageType" + }, "nullable": true, "metadata": { "description": "Optional. Images to create." @@ -1410,12 +1692,14 @@ }, "lock": { "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { "description": "Optional. The lock settings of the service." } }, "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", + "nullable": true, "metadata": { "description": "Optional. Array of role assignments to create." } @@ -1424,16 +1708,10 @@ "type": "object", "nullable": true, "metadata": { + "example": " {\n key1: 'value1'\n key2: 'value2'\n }\n ", "description": "Optional. Tags for all resources." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, "sharingProfile": { "type": "object", "nullable": true, @@ -1450,12 +1728,19 @@ } }, "variables": { - "builtInRoleNames": { + "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -1463,8 +1748,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.compute-gallery.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-gallery.{0}.{1}', replace('0.7.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1482,7 +1767,7 @@ }, "gallery": { "type": "Microsoft.Compute/galleries", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -1509,20 +1794,20 @@ "gallery_roleAssignments": { "copy": { "name": "gallery_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Compute/galleries/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Compute/galleries', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -1586,8 +1871,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "9175012718933553578" + "version": "0.29.47.4906", + "templateHash": "7960057132021914503" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", @@ -1599,6 +1884,13 @@ "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": { @@ -1749,12 +2041,19 @@ } }, "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -1787,20 +2086,20 @@ "application_roleAssignments": { "copy": { "name": "application_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "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": "[guid(resourceId('Microsoft.Compute/galleries/applications', parameters('galleryName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -1857,41 +2156,32 @@ }, "mode": "Incremental", "parameters": { - "location": { - "value": "[parameters('location')]" - }, "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')]" + }, "osType": { "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osType]" }, "osState": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'osState')]" - }, - "publisher": { - "value": "[coalesce(parameters('images'), createArray())[copyIndex()].publisher]" - }, - "offer": { - "value": "[coalesce(parameters('images'), createArray())[copyIndex()].offer]" - }, - "sku": { - "value": "[coalesce(parameters('images'), createArray())[copyIndex()].sku]" + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osState]" }, - "minRecommendedvCPUs": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'minRecommendedvCPUs')]" + "identifier": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].identifier]" }, - "maxRecommendedvCPUs": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'maxRecommendedvCPUs')]" + "vCPUs": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'vCPUs')]" }, - "minRecommendedMemory": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'minRecommendedMemory')]" - }, - "maxRecommendedMemory": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'maxRecommendedMemory')]" + "memory": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'memory')]" }, "hyperVGeneration": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'hyperVGeneration')]" @@ -1902,8 +2192,11 @@ "isAcceleratedNetworkSupported": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isAcceleratedNetworkSupported')]" }, - "description": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'description')]" + "isHibernateSupported": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isHibernateSupported')]" + }, + "architecture": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'architecture')]" }, "eula": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'eula')]" @@ -1914,20 +2207,16 @@ "releaseNoteUri": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'releaseNoteUri')]" }, - "productName": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'productName')]" - }, - "planName": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'planName')]" - }, - "planPublisherName": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'planPublisherName')]" + "purchasePlan": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'purchasePlan')]" }, - "endOfLife": { + "endOfLifeDate": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'endOfLife')]" }, - "excludedDiskTypes": { - "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'excludedDiskTypes')]" + "disallowed": { + "value": { + "diskTypes": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'excludedDiskTypes'), createArray())]" + } }, "roleAssignments": { "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'roleAssignments')]" @@ -1943,8 +2232,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "7059991596058545894" + "version": "0.29.47.4906", + "templateHash": "17284709546040050431" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -1956,6 +2245,13 @@ "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": { @@ -2016,11 +2312,105 @@ } }, "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." } @@ -2039,180 +2429,148 @@ "description": "Conditional. The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment." } }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], + "identifier": { + "$ref": "#/definitions/identifierType", "metadata": { - "description": "Required. OS type of the image to be created." + "description": "Required. This is the gallery image definition identifier." } }, "osState": { "type": "string", - "defaultValue": "Generalized", "allowedValues": [ "Generalized", "Specialized" ], "metadata": { - "description": "Optional. This property allows the user to specify whether the virtual machines created under this image are 'Generalized' or 'Specialized'." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the gallery Image Definition publisher." + "description": "Required. This property allows the user to specify the state of the OS of the image." } }, - "offer": { + "osType": { "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], "metadata": { - "description": "Required. The name of the gallery Image Definition offer." + "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." } }, - "sku": { + "privacyStatementUri": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the gallery Image Definition SKU." - } - }, - "minRecommendedvCPUs": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 128, - "metadata": { - "description": "Optional. The minimum number of the CPU cores recommended for this image." + "description": "Optional. The privacy statement uri." } }, - "maxRecommendedvCPUs": { - "type": "int", - "defaultValue": 4, - "minValue": 1, - "maxValue": 128, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, "metadata": { - "description": "Optional. The maximum number of the CPU cores recommended for this image." + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." } }, - "minRecommendedMemory": { - "type": "int", - "defaultValue": 4, - "minValue": 1, - "maxValue": 4000, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 1, + "max": 4 + }, "metadata": { - "description": "Optional. The minimum amount of RAM in GB recommended for this image." + "description": "Optional. Describes the resource range (1-128 CPU cores)." } }, - "maxRecommendedMemory": { - "type": "int", - "defaultValue": 16, - "minValue": 1, - "maxValue": 4000, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 4, + "max": 16 + }, "metadata": { - "description": "Optional. The maximum amount of RAM in GB recommended for this image." + "description": "Optional. Describes the resource range (1-4000 GB RAM)." } }, - "hyperVGeneration": { + "releaseNoteUri": { "type": "string", "nullable": true, - "allowedValues": [ - "V1", - "V2" - ], "metadata": { - "description": "Optional. The hypervisor generation of the Virtual Machine.\n- If this value is not specified, then it is determined by the securityType parameter.\n- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.\n" + "description": "Optional. The release note uri. Has to be a valid URL." } }, "securityType": { "type": "string", - "defaultValue": "Standard", "allowedValues": [ - "Standard", - "TrustedLaunch", "ConfidentialVM", - "ConfidentialVMSupported" + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch" ], + "nullable": true, "metadata": { "description": "Optional. The security type of the image. Requires a hyperVGeneration V2." } }, - "isHibernateSupported": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifiy if the image supports hibernation." - } - }, "isAcceleratedNetworkSupported": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Specify if the image supports accelerated networking.\nAccelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.\nThis high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.\n" + "description": "Optional. Specify if the image supports accelerated networking." } }, - "description": { - "type": "string", + "isHibernateSupported": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The description of this gallery Image Definition resource. This property is updatable." + "description": "Optional. Specifiy if the image supports hibernation." } }, - "eula": { + "architecture": { "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], "nullable": true, "metadata": { - "description": "Optional. The Eula agreement for the gallery Image Definition. Has to be a valid URL." + "description": "Optional. The architecture of the image. Applicable to OS disks only." } }, - "privacyStatementUri": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The privacy statement uri. Has to be a valid URL." + "description": "Optional. The description of this gallery image definition resource. This property is updatable." } }, - "releaseNoteUri": { - "type": "string", + "disallowed": { + "$ref": "#/definitions/disallowedType", "nullable": true, "metadata": { - "description": "Optional. The release note uri. Has to be a valid URL." + "description": "Optional. Describes the disallowed disk types." } }, - "productName": { + "endOfLifeDate": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The product ID." + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." } }, - "planName": { + "eula": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The plan ID." + "description": "Optional. The Eula agreement for the gallery image definition." } }, - "planPublisherName": { + "hyperVGeneration": { "type": "string", + "allowedValues": [ + "V1", + "V2" + ], "nullable": true, "metadata": { - "description": "Optional. The publisher ID." - } - }, - "endOfLife": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "excludedDiskTypes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of the excluded disk types (e.g., Standard_LRS)." + "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." } }, "roleAssignments": { @@ -2225,17 +2583,25 @@ "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags for all resources." + "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -2243,48 +2609,39 @@ "gallery": { "existing": true, "type": "Microsoft.Compute/galleries", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[parameters('galleryName')]" }, "image": { "type": "Microsoft.Compute/galleries/images", - "apiVersion": "2022-03-03", + "apiVersion": "2023-07-03", "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "osType": "[parameters('osType')]", - "osState": "[parameters('osState')]", - "identifier": { - "publisher": "[parameters('publisher')]", - "offer": "[parameters('offer')]", - "sku": "[parameters('sku')]" - }, - "recommended": { - "vCPUs": { - "min": "[parameters('minRecommendedvCPUs')]", - "max": "[parameters('maxRecommendedvCPUs')]" - }, - "memory": { - "min": "[parameters('minRecommendedMemory')]", - "max": "[parameters('maxRecommendedMemory')]" - } - }, - "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(parameters('securityType'))), 'V2', 'V1'))]", - "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported'))), createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), if(not(equals(parameters('securityType'), 'Standard')), createArray(createObject('name', 'SecurityType', 'value', parameters('securityType'))), createArray()))]", + "architecture": "[parameters('architecture')]", "description": "[parameters('description')]", + "disallowed": { + "diskTypes": "[coalesce(tryGet(parameters('disallowed'), 'diskTypes'), createArray())]" + }, + "endOfLifeDate": "[parameters('endOfLifeDate')]", "eula": "[parameters('eula')]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), 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()))]", + "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')]", - "releaseNoteUri": "[parameters('releaseNoteUri')]", - "purchasePlan": { - "product": "[parameters('productName')]", - "name": "[parameters('planName')]", - "publisher": "[parameters('planPublisherName')]" + "purchasePlan": "[coalesce(parameters('purchasePlan'), null())]", + "recommended": { + "vCPUs": "[parameters('vCPUs')]", + "memory": "[parameters('memory')]" }, - "endOfLifeDate": "[parameters('endOfLife')]", - "disallowed": { - "diskTypes": "[parameters('excludedDiskTypes')]" - } + "releaseNoteUri": "[parameters('releaseNoteUri')]" }, "dependsOn": [ "gallery" @@ -2293,20 +2650,20 @@ "image_roleAssignments": { "copy": { "name": "image_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "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": "[guid(resourceId('Microsoft.Compute/galleries/images', parameters('galleryName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -2340,7 +2697,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('image', '2022-03-03', 'full').location]" + "value": "[reference('image', '2023-07-03', 'full').location]" } } } @@ -2377,7 +2734,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('gallery', '2022-03-03', 'full').location]" + "value": "[reference('gallery', '2023-07-03', 'full').location]" }, "imageResourceIds": { "type": "array", @@ -2423,9 +2780,7 @@ "addressPrefix": "[parameters('virtualNetworkSubnetAddressPrefix')]", "privateLinkServiceNetworkPolicies": "Disabled", "serviceEndpoints": [ - { - "service": "Microsoft.Storage" - } + "Microsoft.Storage" ] }, { @@ -2433,18 +2788,9 @@ "addressPrefix": "[parameters('virtualNetworkDeploymentScriptSubnetAddressPrefix')]", "privateLinkServiceNetworkPolicies": "Disabled", "serviceEndpoints": [ - { - "service": "Microsoft.Storage" - } + "Microsoft.Storage" ], - "delegations": [ - { - "name": "Microsoft.ContainerInstance.containerGroups", - "properties": { - "serviceName": "Microsoft.ContainerInstance/containerGroups" - } - } - ] + "delegation": "Microsoft.ContainerInstance/containerGroups" } ] }, @@ -2462,8 +2808,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "18408205474040416108" + "version": "0.29.47.4906", + "templateHash": "15949466154563447171" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -2500,6 +2846,13 @@ "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": { @@ -2649,37 +3002,273 @@ "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." - } + "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 + }, + "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" }, - "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." - } + "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" + ], + "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": { + "$ref": "#/definitions/roleAssignmentType", + "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" }, - "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." - } + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" }, - "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, + "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." } } - }, - "nullable": true + } } }, "parameters": { @@ -2702,32 +3291,48 @@ "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", - "defaultValue": [], + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, "metadata": { "description": "Optional. An Array of subnets to deploy to the Virtual Network." } }, "dnsServers": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { "description": "Optional. DNS Servers associated to the Virtual Network." } }, "ddosProtectionPlanResourceId": { "type": "string", - "defaultValue": "", + "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", - "defaultValue": [], + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, "metadata": { - "description": "Optional. Virtual Network Peerings configurations." + "description": "Optional. Virtual Network Peering configurations." } }, "vnetEncryption": { @@ -2787,15 +3392,29 @@ "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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "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')]" } }, @@ -2803,8 +3422,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.1.6', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2822,42 +3441,21 @@ }, "virtualNetwork": { "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-04-01", + "apiVersion": "2024-01-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')]" }, + "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())]" + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" } }, "virtualNetwork_lock": { @@ -2918,20 +3516,20 @@ "virtualNetwork_roleAssignments": { "copy": { "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -2940,7 +3538,7 @@ "virtualNetwork_subnets": { "copy": { "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", "mode": "serial", "batchSize": 1 }, @@ -2957,23 +3555,50 @@ "value": "[parameters('name')]" }, "name": { - "value": "[parameters('subnets')[copyIndex()].name]" + "value": "[coalesce(parameters('subnets'), createArray())[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()))]" + "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#", @@ -2982,8 +3607,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "17306638026226376877" + "version": "0.29.47.4906", + "templateHash": "5699372618313647761" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -2995,6 +3620,13 @@ "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": { @@ -3061,7 +3693,7 @@ "name": { "type": "string", "metadata": { - "description": "Optional. The Name of the subnet resource." + "description": "Requird. The Name of the subnet resource." } }, "virtualNetworkName": { @@ -3072,41 +3704,45 @@ }, "addressPrefix": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The address prefix for the subnet." + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." } }, "networkSecurityGroupResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the network security group to assign to the subnet." } }, "routeTableResourceId": { "type": "string", - "defaultValue": "", + "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." } }, - "delegations": { - "type": "array", - "defaultValue": [], + "delegation": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. The delegations to enable on the subnet." + "description": "Optional. The delegation to enable on the subnet." } }, "natGatewayResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." } @@ -3120,7 +3756,7 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." } }, "privateLinkServiceNetworkPolicies": { @@ -3132,28 +3768,42 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." } }, "addressPrefixes": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. List of address prefixes for the subnet." + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." } }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "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." } }, - "ipAllocations": { + "applicationGatewayIPConfigurations": { "type": "array", "defaultValue": [], "metadata": { - "description": "Optional. Array of IpAllocation which reference this subnet." + "description": "Optional. Application gateway IP configurations of virtual network resource." } }, "serviceEndpointPolicies": { @@ -3171,12 +3821,19 @@ } }, "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')]", + "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')]" } }, @@ -3184,26 +3841,35 @@ "virtualNetwork": { "existing": true, "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-04-01", + "apiVersion": "2024-01-01", "name": "[parameters('virtualNetworkName')]" }, "subnet": { "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2023-04-01", + "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())]", - "serviceEndpoints": "[parameters('serviceEndpoints')]", - "delegations": "[parameters('delegations')]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", "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')]" + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" }, "dependsOn": [ "virtualNetwork" @@ -3212,20 +3878,20 @@ "subnet_roleAssignments": { "copy": { "name": "subnet_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "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": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "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": "[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')]" + "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" @@ -3254,19 +3920,19 @@ }, "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" }, - "subnetAddressPrefix": { + "addressPrefix": { "type": "string", "metadata": { "description": "The address prefix for the subnet." }, - "value": "[reference('subnet').addressPrefix]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" }, - "subnetAddressPrefixes": { + "addressPrefixes": { "type": "array", "metadata": { "description": "List of address prefixes for the subnet." }, - "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" } } } @@ -3278,7 +3944,7 @@ "virtualNetwork_peering_local": { "copy": { "name": "virtualNetwork_peering_local", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -3292,15 +3958,27 @@ "localVnetName": { "value": "[parameters('name')]" }, - "remoteVirtualNetworkId": { - "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + "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')]" }, - "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()))]" + "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#", @@ -3308,8 +3986,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "17624189975510507274" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3318,9 +3996,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -3329,7 +4007,7 @@ "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": { + "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." @@ -3374,7 +4052,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-04-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -3383,7 +4061,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -3420,14 +4098,14 @@ "virtualNetwork_peering_remote": { "copy": { "name": "virtualNetwork_peering_remote", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, - "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", + "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(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", - "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -3435,17 +4113,29 @@ "mode": "Incremental", "parameters": { "localVnetName": { - "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "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()))]" + "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#", @@ -3453,8 +4143,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.170.59819", - "templateHash": "17624189975510507274" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3463,9 +4153,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -3474,7 +4164,7 @@ "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": { + "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." @@ -3519,7 +4209,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-04-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -3528,7 +4218,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -3591,8 +4281,8 @@ "description": "The names of the deployed subnets." }, "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[parameters('subnets')[copyIndex()].name]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" } }, "subnetResourceIds": { @@ -3601,8 +4291,8 @@ "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)]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" } }, "location": { @@ -3610,7 +4300,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('virtualNetwork', '2023-04-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" } } } @@ -13068,7 +13758,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "10563518610969019714" + "templateHash": "5978422939896103340" }, "name": "Deployment Scripts", "description": "This module deploys Deployment Scripts.", @@ -13407,7 +14097,7 @@ "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')]", + "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": { @@ -13431,7 +14121,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -13643,7 +14333,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "3107459634056863407" + "templateHash": "18298474056790033884" }, "name": "Virtual Machine Image Templates", "description": "This module deploys a Virtual Machine Image Template that can be consumed by Azure Image Builder (AIB).", @@ -14196,7 +14886,7 @@ "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')]", + "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')]" } }, @@ -14205,7 +14895,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.virtualmachineimages-imagetemplate.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.virtualmachineimages-imagetemplate.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -14403,7 +15093,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "10563518610969019714" + "templateHash": "5978422939896103340" }, "name": "Deployment Scripts", "description": "This module deploys Deployment Scripts.", @@ -14742,7 +15432,7 @@ "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')]", + "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": { @@ -14766,7 +15456,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -14973,7 +15663,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "10563518610969019714" + "templateHash": "5978422939896103340" }, "name": "Deployment Scripts", "description": "This module deploys Deployment Scripts.", @@ -15312,7 +16002,7 @@ "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')]", + "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": { @@ -15336,7 +16026,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/defaults/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/defaults/main.test.bicep index a96ed2e5b9..26d33bbc33 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/defaults/main.test.bicep +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/defaults/main.test.bicep @@ -41,9 +41,12 @@ module testDeployment '../../../main.bicep' = [ hyperVGeneration: 'V2' name: 'sid-linux' osType: 'Linux' - publisher: 'devops' - offer: 'devops_linux' - sku: 'devops_linux_az' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' } ] imageTemplateImageSource: { diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/main.test.bicep index 81918c04b0..e6c00b9003 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/main.test.bicep +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/main.test.bicep @@ -46,9 +46,12 @@ module testDeployment '../../../main.bicep' = [ hyperVGeneration: 'V2' name: computeGalleryImageDefinitionName osType: 'Linux' - publisher: 'devops' - offer: 'devops_linux' - sku: 'devops_linux_az' + osState: 'Generalized' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } } ] storageAccountFilesToUpload: [ diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/dependencies.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/dependencies.bicep index ca5c99c459..be25388fde 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/dependencies.bicep +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/dependencies.bicep @@ -40,9 +40,12 @@ var computeGalleryImageDefinitionsVar = [ hyperVGeneration: 'V2' name: 'sid-linux' osType: 'Linux' - publisher: 'devops' - offer: 'devops_linux' - sku: 'devops_linux_az' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' } ] var assetsStorageAccountContainerName = 'aibscripts' @@ -64,7 +67,7 @@ resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { } // Always deployed as both an infra element & needed as a staging resource group for image building -module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.2.4' = { +module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.4.0' = { name: '${deployment().name}-image-rg' params: { name: imageTemplateResourceGroupName @@ -73,7 +76,7 @@ module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.2.4' = { } // User Assigned Identity (MSI) -module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = { +module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { name: '${deployment().name}-ds-msi' scope: rg params: { @@ -82,7 +85,7 @@ module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = } } -module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = { +module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { name: '${deployment().name}-image-msi' scope: rg params: { @@ -102,7 +105,7 @@ resource imageMSI_rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { } // Azure Compute Gallery -module azureComputeGallery 'br/public:avm/res/compute/gallery:0.4.0' = { +module azureComputeGallery 'br/public:avm/res/compute/gallery:0.7.0' = { name: '${deployment().name}-acg' scope: rg params: { @@ -113,7 +116,7 @@ module azureComputeGallery 'br/public:avm/res/compute/gallery:0.4.0' = { } // Image Template Virtual Network -module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = { +module vnet 'br/public:avm/res/network/virtual-network:0.4.0' = { name: '${deployment().name}-vnet' scope: rg params: { @@ -127,9 +130,7 @@ module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = { addressPrefix: cidrSubnet(addressPrefix, 24, 0) privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } + 'Microsoft.Storage' ] } { @@ -137,18 +138,9 @@ module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = { addressPrefix: cidrSubnet(addressPrefix, 24, 1) privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET - temp serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } - ] - delegations: [ - { - name: 'Microsoft.ContainerInstance.containerGroups' - properties: { - serviceName: 'Microsoft.ContainerInstance/containerGroups' - } - } + 'Microsoft.Storage' ] + delegation: 'Microsoft.ContainerInstance/containerGroups' } ] location: location diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyBase/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyBase/main.test.bicep index 1735445bde..720941b1e9 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyBase/main.test.bicep +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyBase/main.test.bicep @@ -42,9 +42,12 @@ module testDeployment '../../../main.bicep' = [ hyperVGeneration: 'V2' name: computeGalleryImageDefinitionName osType: 'Linux' - publisher: 'devops' - offer: 'devops_linux' - sku: 'devops_linux_az' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' } ] imageTemplateImageSource: { diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/dependencies.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/dependencies.bicep index fe793a0e85..7a4eb4a7c3 100644 --- a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/dependencies.bicep +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/dependencies.bicep @@ -44,9 +44,12 @@ var computeGalleryImageDefinitionsVar = [ hyperVGeneration: 'V2' name: 'sid-linux' osType: 'Linux' - publisher: 'devops' - offer: 'devops_linux' - sku: 'devops_linux_az' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' } ] var assetsStorageAccountContainerName = 'aibscripts' @@ -68,7 +71,7 @@ resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { } // Always deployed as both an infra element & needed as a staging resource group for image building -module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.2.4' = { +module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.4.0' = { name: '${deployment().name}-image-rg' params: { name: imageTemplateResourceGroupName @@ -77,7 +80,7 @@ module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.2.4' = { } // User Assigned Identity (MSI) -module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = { +module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { name: '${deployment().name}-ds-msi' scope: rg params: { @@ -86,7 +89,7 @@ module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = } } -module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.2' = { +module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { name: '${deployment().name}-image-msi' scope: rg params: { @@ -106,7 +109,7 @@ resource imageMSI_rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { } // Azure Compute Gallery -module azureComputeGallery 'br/public:avm/res/compute/gallery:0.4.0' = { +module azureComputeGallery 'br/public:avm/res/compute/gallery:0.7.0' = { name: '${deployment().name}-acg' scope: rg params: { @@ -117,7 +120,7 @@ module azureComputeGallery 'br/public:avm/res/compute/gallery:0.4.0' = { } // Image Template Virtual Network -module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = { +module vnet 'br/public:avm/res/network/virtual-network:0.4.0' = { name: '${deployment().name}-vnet' scope: rg params: { @@ -131,9 +134,7 @@ module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = { addressPrefix: cidrSubnet(addressPrefix, 24, 0) privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } + 'Microsoft.Storage' ] } { @@ -141,18 +142,9 @@ module vnet 'br/public:avm/res/network/virtual-network:0.1.6' = { addressPrefix: cidrSubnet(addressPrefix, 24, 1) privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET - temp serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } - ] - delegations: [ - { - name: 'Microsoft.ContainerInstance.containerGroups' - properties: { - serviceName: 'Microsoft.ContainerInstance/containerGroups' - } - } + 'Microsoft.Storage' ] + delegation: 'Microsoft.ContainerInstance/containerGroups' } ] location: location @@ -227,7 +219,7 @@ module dsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { } // Upload storage account files -module storageAccount_upload 'br/public:avm/res/resources/deployment-script:0.3.1' = { +module storageAccount_upload 'br/public:avm/res/resources/deployment-script:0.4.0' = { name: '${deployment().name}-storage-upload-ds' scope: resourceGroup(resourceGroupName) params: { From da863cb4d2b10daa592f11d6b8c284d835c64ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= Date: Tue, 8 Oct 2024 08:20:53 +0200 Subject: [PATCH 38/93] fix: Readme - bicepparam Examples - Exception handling and missing Readme modification (#3442) ## Description Fixes an Exception in the script and adds a missing Readme ## Pipeline Reference | Pipeline | | -------- | | | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/db-for-my-sql/flexible-server/README.md | 2 +- .../pipelines/sharedScripts/Set-ModuleReadMe.ps1 | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/avm/res/db-for-my-sql/flexible-server/README.md b/avm/res/db-for-my-sql/flexible-server/README.md index 428d5be284..bda2a9c1e3 100644 --- a/avm/res/db-for-my-sql/flexible-server/README.md +++ b/avm/res/db-for-my-sql/flexible-server/README.md @@ -16,7 +16,7 @@ This module deploys a DBforMySQL Flexible Server. | :-- | :-- | | `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.DBforMySQL/flexibleServers` | [2023-12-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/flexibleServers) | +| `Microsoft.DBforMySQL/flexibleServers` | [2023-12-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-12-30/flexibleServers) | | `Microsoft.DBforMySQL/flexibleServers/administrators` | [2023-06-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-06-30/flexibleServers/administrators) | | `Microsoft.DBforMySQL/flexibleServers/databases` | [2023-06-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-06-30/flexibleServers/databases) | | `Microsoft.DBforMySQL/flexibleServers/firewallRules` | [2023-06-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-06-30/flexibleServers/firewallRules) | diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 5d27ba34e7..2562eb4eb9 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -1609,13 +1609,15 @@ function Set-UsageExamplesSection { $bicepExample = ConvertTo-FormattedBicep @conversionInputObject # [6/6] Convert the Bicep format to a Bicep parameters file format - $bicepParamBlockArray = $bicepExample -split '\r?\n' - $topLevelParamIndent = ([regex]::Match($bicepParamBlockArray[0], '^(\s+).*')).Captures.Groups[1].Value.Length - $bicepParametersFileExample = $bicepParamBlockArray | ForEach-Object { - $line = $_ - $line = $line -replace "^(\s{$topLevelParamIndent})([a-zA-Z]*)(:)(.*)", 'param $2 =$4' # Update any [ xyz: abc] to [param xyz = abc] - $line = $line -replace "^\s{$topLevelParamIndent}", '' # Update any [ xyz: abc] to [xyz: abc] - $line + if ($bicepExample.length -gt 0) { + $bicepParamBlockArray = $bicepExample -split '\r?\n' + $topLevelParamIndent = ([regex]::Match($bicepParamBlockArray[0], '^(\s+).*')).Captures.Groups[1].Value.Length + $bicepParametersFileExample = $bicepParamBlockArray | ForEach-Object { + $line = $_ + $line = $line -replace "^(\s{$topLevelParamIndent})([a-zA-Z]*)(:)(.*)", 'param $2 =$4' # Update any [ xyz: abc] to [param xyz = abc] + $line = $line -replace "^\s{$topLevelParamIndent}", '' # Update any [ xyz: abc] to [xyz: abc] + $line + } } # --------------------- # From 41479d62af8c8b3df5959158cfdeeacaf113132a Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 8 Oct 2024 09:54:57 +0200 Subject: [PATCH 39/93] fix: Fixed use of Gallery-Image SecurityType parameter value 'Standard' and added additional types (#3450) ## Description - Fixed use of Gallery-Image SecurityType parameter value 'Standard' ('Standard' should not be set) - Added additional types ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.compute.gallery](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml/badge.svg?branch=users%2Falsehr%2FgallerySecurityType&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/res/compute/gallery/README.md | 8 +++-- avm/res/compute/gallery/application/main.json | 4 +-- avm/res/compute/gallery/image/README.md | 2 ++ avm/res/compute/gallery/image/main.bicep | 10 ++++-- avm/res/compute/gallery/image/main.json | 10 +++--- avm/res/compute/gallery/main.bicep | 12 ++++++- avm/res/compute/gallery/main.json | 31 +++++++++++++------ .../gallery/tests/e2e/max/main.test.bicep | 2 +- 8 files changed, 57 insertions(+), 22 deletions(-) diff --git a/avm/res/compute/gallery/README.md b/avm/res/compute/gallery/README.md index d0b76a9c34..46b2362993 100644 --- a/avm/res/compute/gallery/README.md +++ b/avm/res/compute/gallery/README.md @@ -206,7 +206,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = { product: 'testProduct' publisher: 'testPublisher' } - securityType: 'TrustedLaunch' + securityType: 'Standard' vCPUs: { max: 8 min: 2 @@ -436,7 +436,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = { "product": "testProduct", "publisher": "testPublisher" }, - "securityType": "TrustedLaunch", + "securityType": "Standard", "vCPUs": { "max": 8, "min": 2 @@ -668,7 +668,7 @@ param images = [ product: 'testProduct' publisher: 'testPublisher' } - securityType: 'TrustedLaunch' + securityType: 'Standard' vCPUs: { max: 8 min: 2 @@ -1243,6 +1243,8 @@ The security type of the image. Requires a hyperVGeneration V2. Defaults to `Sta 'ConfidentialVMSupported' 'Standard' 'TrustedLaunch' + 'TrustedLaunchAndConfidentialVmSupported' + 'TrustedLaunchSupported' ] ``` diff --git a/avm/res/compute/gallery/application/main.json b/avm/res/compute/gallery/application/main.json index bdc767825b..42db0c54ff 100644 --- a/avm/res/compute/gallery/application/main.json +++ b/avm/res/compute/gallery/application/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7960057132021914503" + "version": "0.30.23.60470", + "templateHash": "13081960860160182257" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", diff --git a/avm/res/compute/gallery/image/README.md b/avm/res/compute/gallery/image/README.md index 484444ae23..c8ee79aeb5 100644 --- a/avm/res/compute/gallery/image/README.md +++ b/avm/res/compute/gallery/image/README.md @@ -432,6 +432,8 @@ The security type of the image. Requires a hyperVGeneration V2. 'ConfidentialVMSupported' 'Standard' 'TrustedLaunch' + 'TrustedLaunchAndConfidentialVmSupported' + 'TrustedLaunchSupported' ] ``` diff --git a/avm/res/compute/gallery/image/main.bicep b/avm/res/compute/gallery/image/main.bicep index 808b755df2..f719228f82 100644 --- a/avm/res/compute/gallery/image/main.bicep +++ b/avm/res/compute/gallery/image/main.bicep @@ -39,7 +39,13 @@ param memory resourceRangeType = { min: 4, max: 16 } param releaseNoteUri string? @sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2.') -param securityType ('Standard' | 'TrustedLaunch' | 'ConfidentialVM' | 'ConfidentialVMSupported')? +param securityType ( + | 'Standard' + | 'ConfidentialVM' + | 'TrustedLaunchSupported' + | 'TrustedLaunch' + | 'TrustedLaunchAndConfidentialVmSupported' + | 'ConfidentialVMSupported')? @sys.description('Optional. Specify if the image supports accelerated networking.') param isAcceleratedNetworkSupported bool = true @@ -132,7 +138,7 @@ resource image 'Microsoft.Compute/galleries/images@2023-07-03' = { value: '${isAcceleratedNetworkSupported}' } ], - (securityType != null + (securityType != null && securityType != 'Standard' // Standard is the default and is not set ? [ { name: 'SecurityType' diff --git a/avm/res/compute/gallery/image/main.json b/avm/res/compute/gallery/image/main.json index 941b51a87c..aede5e97ac 100644 --- a/avm/res/compute/gallery/image/main.json +++ b/avm/res/compute/gallery/image/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17284709546040050431" + "version": "0.30.23.60470", + "templateHash": "5984025187928110337" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -275,7 +275,9 @@ "ConfidentialVM", "ConfidentialVMSupported", "Standard", - "TrustedLaunch" + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" ], "nullable": true, "metadata": { @@ -399,7 +401,7 @@ }, "endOfLifeDate": "[parameters('endOfLifeDate')]", "eula": "[parameters('eula')]", - "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), 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()))]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), 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()))]", "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", "identifier": { "publisher": "[parameters('identifier').publisher]", diff --git a/avm/res/compute/gallery/main.bicep b/avm/res/compute/gallery/main.bicep index b93b444a27..44ed9c41f6 100644 --- a/avm/res/compute/gallery/main.bicep +++ b/avm/res/compute/gallery/main.bicep @@ -214,6 +214,7 @@ output imageResourceIds array = [ // Definitions // // =============== // +@export() type lockType = { @sys.description('Optional. Specify the name of lock.') name: string? @@ -222,6 +223,7 @@ type lockType = { kind: ('CanNotDelete' | 'ReadOnly' | 'None')? } +@export() type roleAssignmentType = { @sys.description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') name: string? @@ -249,6 +251,8 @@ type roleAssignmentType = { }[] import { identifierType, purchasePlanType, resourceRangeType } from './image/main.bicep' + +@export() type imageType = { @sys.description('Required. Name of the image definition.') @minLength(1) @@ -277,7 +281,13 @@ type imageType = { hyperVGeneration: ('V1' | 'V2')? @sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`.') - securityType: ('Standard' | 'TrustedLaunch' | 'ConfidentialVM' | 'ConfidentialVMSupported')? + securityType: ( + | 'Standard' + | 'ConfidentialVM' + | 'TrustedLaunchSupported' + | 'TrustedLaunch' + | 'TrustedLaunchAndConfidentialVmSupported' + | 'ConfidentialVMSupported')? @sys.description('Optional. Specify if the image supports accelerated networking. Defaults to true.') isAcceleratedNetworkSupported: bool? diff --git a/avm/res/compute/gallery/main.json b/avm/res/compute/gallery/main.json index d0346696e2..d2b8bfe98a 100644 --- a/avm/res/compute/gallery/main.json +++ b/avm/res/compute/gallery/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16056066182123599311" + "version": "0.30.23.60470", + "templateHash": "17783194818453553981" }, "name": "Azure Compute Galleries", "description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).", @@ -35,6 +35,9 @@ "description": "Optional. Specify the type of lock." } } + }, + "metadata": { + "__bicep_export!": true } }, "roleAssignmentType": { @@ -107,6 +110,9 @@ } } } + }, + "metadata": { + "__bicep_export!": true } }, "imageType": { @@ -184,7 +190,9 @@ "ConfidentialVM", "ConfidentialVMSupported", "Standard", - "TrustedLaunch" + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" ], "nullable": true, "metadata": { @@ -261,6 +269,9 @@ "description": "Optional. Describes the disallowed disk types." } } + }, + "metadata": { + "__bicep_export!": true } }, "identifierType": { @@ -573,8 +584,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7960057132021914503" + "version": "0.30.23.60470", + "templateHash": "13081960860160182257" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", @@ -934,8 +945,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17284709546040050431" + "version": "0.30.23.60470", + "templateHash": "5984025187928110337" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -1204,7 +1215,9 @@ "ConfidentialVM", "ConfidentialVMSupported", "Standard", - "TrustedLaunch" + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" ], "nullable": true, "metadata": { @@ -1328,7 +1341,7 @@ }, "endOfLifeDate": "[parameters('endOfLifeDate')]", "eula": "[parameters('eula')]", - "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), 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()))]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), 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()))]", "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", "identifier": { "publisher": "[parameters('identifier').publisher]", diff --git a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep index f094c884e9..a29b6ff7c8 100644 --- a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep +++ b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep @@ -135,7 +135,7 @@ module testDeployment '../../../main.bicep' = [ } { name: '${namePrefix}-az-imgd-wdtl-003' - securityType: 'TrustedLaunch' + securityType: 'Standard' osType: 'Windows' osState: 'Generalized' hyperVGeneration: 'V2' From c12a502b13be8a2ddd81655a99eb662e43216010 Mon Sep 17 00:00:00 2001 From: Zach Trocinski Date: Tue, 8 Oct 2024 14:41:02 -0500 Subject: [PATCH 40/93] Initial ptn modules for policy exemptions --- ...avm.ptn.authorization.policy-exemption.yml | 88 +++ .../authorization/policy-exemption/README.md | 311 +++++++++ .../authorization/policy-exemption/main.bicep | 149 ++++ .../authorization/policy-exemption/main.json | 650 ++++++++++++++++++ .../modules/management-group.bicep | 68 ++ .../modules/resource-group.bicep | 68 ++ .../modules/subscription.bicep | 68 ++ .../tests/e2e/defaults/main.test.bicep | 48 ++ .../tests/e2e/waf-aligned/main.test.bicep | 48 ++ .../policy-exemption/version.json | 7 + 10 files changed, 1505 insertions(+) create mode 100644 .github/workflows/avm.ptn.authorization.policy-exemption.yml create mode 100644 avm/ptn/authorization/policy-exemption/README.md create mode 100644 avm/ptn/authorization/policy-exemption/main.bicep create mode 100644 avm/ptn/authorization/policy-exemption/main.json create mode 100644 avm/ptn/authorization/policy-exemption/modules/management-group.bicep create mode 100644 avm/ptn/authorization/policy-exemption/modules/resource-group.bicep create mode 100644 avm/ptn/authorization/policy-exemption/modules/subscription.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/version.json diff --git a/.github/workflows/avm.ptn.authorization.policy-exemption.yml b/.github/workflows/avm.ptn.authorization.policy-exemption.yml new file mode 100644 index 0000000000..5c68e6f925 --- /dev/null +++ b/.github/workflows/avm.ptn.authorization.policy-exemption.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.authorization.policy-exemption" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.authorization.policy-exemption.yml" + - "avm/ptn/authorization/policy-exemption/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/authorization/policy-exemption" + workflowPath: ".github/workflows/avm.ptn.authorization.policy-exemption.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/authorization/policy-exemption/README.md b/avm/ptn/authorization/policy-exemption/README.md new file mode 100644 index 0000000000..30387c930b --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/README.md @@ -0,0 +1,311 @@ +# 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:`. + +- [Defaults](#example-1-defaults) +- [Waf-Aligned](#example-2-waf-aligned) + +### Example 1: _Defaults_ + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + name: 'apedef001' + 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": "apedef001" + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

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

+ +### Example 2: _Waf-Aligned_ + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + name: 'apewaf001' + 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": "apewaf001" + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

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

+ +## 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: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Default' + 'DoNotValidate' + ] + ``` + +### 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 exemption. 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: `expiresOn` + +The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption. + +- Required: Yes +- 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 +- Default: `{}` + +### 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 +- Default: `[]` + +### Parameter: `resourceGroupName` + +The Target Scope for the Policy. The name of the resource group for the policy exemption. + +- 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 exemptions based on factors like resource location, resource type, or whether a resource has a location. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `subscriptionId` + +The Target Scope for the Policy. The subscription ID of the subscription for the policy exemption. + +- Required: No +- Type: string +- Default: `''` + +## 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/ptn/authorization/policy-exemption/main.bicep b/avm/ptn/authorization/policy-exemption/main.bicep new file mode 100644 index 0000000000..a62bf4a7dc --- /dev/null +++ b/avm/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.' +metadata owner = 'Azure/module-maintainers' + +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 + +@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(32) +@minLength(32) +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 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 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: !empty(description) ? description : null + displayName: !empty(displayName) ? displayName : null + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: !empty(expiresOn) ? expiresOn : '' + metadata: !empty(metadata) ? metadata : null + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : null + } +} + +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: !empty(description) ? description : null + displayName: !empty(displayName) ? displayName : null + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: !empty(expiresOn) ? expiresOn : '' + metadata: !empty(metadata) ? metadata : null + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : null + } +} + +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: !empty(description) ? description : null + displayName: !empty(displayName) ? displayName : null + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: !empty(expiresOn) ? expiresOn : '' + metadata: !empty(metadata) ? metadata : null + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : null + } +} + +@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/ptn/authorization/policy-exemption/main.json b/avm/ptn/authorization/policy-exemption/main.json new file mode 100644 index 0000000000..03ddf3caa4 --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/main.json @@ -0,0 +1,650 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "16386010349106137044" + }, + "name": "Policy Exemptions (All scopes)", + "description": "This module deploys a Policy Exemption at a Management Group, Subscription or Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "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", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment 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 exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "minLength": 32, + "maxLength": 32, + "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", + "defaultValue": {}, + "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", + "defaultValue": [], + "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", + "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 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", + "defaultValue": "", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy exemption." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "", + "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": [ + { + "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" + } + } + } + } + }, + { + "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": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', null()))]", + "displayName": "[if(not(empty(parameters('displayName'))), createObject('value', parameters('displayName')), createObject('value', null()))]", + "assignmentScopeValidation": { + "value": "[parameters('assignmentScopeValidation')]" + }, + "exemptionCategory": { + "value": "[parameters('exemptionCategory')]" + }, + "expiresOn": "[if(not(empty(parameters('expiresOn'))), createObject('value', parameters('expiresOn')), createObject('value', ''))]", + "metadata": "[if(not(empty(parameters('metadata'))), createObject('value', parameters('metadata')), createObject('value', null()))]", + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceIds": "[if(not(empty(parameters('policyDefinitionReferenceIds'))), createObject('value', parameters('policyDefinitionReferenceIds')), createObject('value', null()))]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "10692808437895827112" + }, + "name": "Policy Exemptions (Management Group scope)", + "description": "This module deploys a policy exemption at a Management Group scope.", + "owner": "Azure/module-maintainers" + }, + "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", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment 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 exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "minLength": 32, + "maxLength": 32, + "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", + "defaultValue": {}, + "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", + "defaultValue": [], + "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", + "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 exemptions based on factors like resource location, resource type, or whether a resource has a location." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "[parameters('name')]", + "properties": { + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "assignmentScopeValidation": "[parameters('assignmentScopeValidation')]", + "exemptionCategory": "[parameters('exemptionCategory')]", + "expiresOn": "[if(not(empty(parameters('expiresOn'))), parameters('expiresOn'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": "[if(not(empty(parameters('policyDefinitionReferenceIds'))), parameters('policyDefinitionReferenceIds'), null())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), null())]" + } + } + ], + "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'))]" + } + } + } + } + }, + { + "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": "[parameters('subscriptionId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', null()))]", + "displayName": "[if(not(empty(parameters('displayName'))), createObject('value', parameters('displayName')), createObject('value', null()))]", + "assignmentScopeValidation": { + "value": "[parameters('assignmentScopeValidation')]" + }, + "exemptionCategory": { + "value": "[parameters('exemptionCategory')]" + }, + "expiresOn": "[if(not(empty(parameters('expiresOn'))), createObject('value', parameters('expiresOn')), createObject('value', ''))]", + "metadata": "[if(not(empty(parameters('metadata'))), createObject('value', parameters('metadata')), createObject('value', null()))]", + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceIds": "[if(not(empty(parameters('policyDefinitionReferenceIds'))), createObject('value', parameters('policyDefinitionReferenceIds')), createObject('value', null()))]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "6471026360194122026" + }, + "name": "Policy Exemptions (Subscription scope)", + "description": "This module deploys a policy exemption at a Subscription scope.", + "owner": "Azure/module-maintainers" + }, + "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", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment 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 exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "minLength": 32, + "maxLength": 32, + "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", + "defaultValue": {}, + "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", + "defaultValue": [], + "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", + "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 exemptions based on factors like resource location, resource type, or whether a resource has a location." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "[parameters('name')]", + "properties": { + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "assignmentScopeValidation": "[parameters('assignmentScopeValidation')]", + "exemptionCategory": "[parameters('exemptionCategory')]", + "expiresOn": "[if(not(empty(parameters('expiresOn'))), parameters('expiresOn'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": "[if(not(empty(parameters('policyDefinitionReferenceIds'))), parameters('policyDefinitionReferenceIds'), null())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), null())]" + } + } + ], + "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'))]" + } + } + } + } + }, + { + "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": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', null()))]", + "displayName": "[if(not(empty(parameters('displayName'))), createObject('value', parameters('displayName')), createObject('value', null()))]", + "assignmentScopeValidation": { + "value": "[parameters('assignmentScopeValidation')]" + }, + "exemptionCategory": { + "value": "[parameters('exemptionCategory')]" + }, + "expiresOn": "[if(not(empty(parameters('expiresOn'))), createObject('value', parameters('expiresOn')), createObject('value', ''))]", + "metadata": "[if(not(empty(parameters('metadata'))), createObject('value', parameters('metadata')), createObject('value', null()))]", + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceIds": "[if(not(empty(parameters('policyDefinitionReferenceIds'))), createObject('value', parameters('policyDefinitionReferenceIds')), createObject('value', null()))]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "6225706394162525731" + }, + "name": "Policy Exemptions (Resource Group scope)", + "description": "This module deploys a policy exemption at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "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", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment 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 exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "minLength": 32, + "maxLength": 32, + "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", + "defaultValue": {}, + "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", + "defaultValue": [], + "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", + "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 exemptions based on factors like resource location, resource type, or whether a resource has a location." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "[parameters('name')]", + "properties": { + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "assignmentScopeValidation": "[parameters('assignmentScopeValidation')]", + "exemptionCategory": "[parameters('exemptionCategory')]", + "expiresOn": "[if(not(empty(parameters('expiresOn'))), parameters('expiresOn'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": "[if(not(empty(parameters('policyDefinitionReferenceIds'))), parameters('policyDefinitionReferenceIds'), null())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), null())]" + } + } + ], + "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(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyExemption-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}-PolicyExemption-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}-PolicyExemption-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Exemption resource ID." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyExemption-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}-PolicyExemption-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}-PolicyExemption-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value))]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/authorization/policy-exemption/modules/management-group.bicep b/avm/ptn/authorization/policy-exemption/modules/management-group.bicep new file mode 100644 index 0000000000..eb5d13b81b --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/modules/management-group.bicep @@ -0,0 +1,68 @@ +metadata name = 'Policy Exemptions (Management Group scope)' +metadata description = 'This module deploys a policy exemption at a Management Group scope.' +metadata owner = 'Azure/module-maintainers' + +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 + +@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(32) +@minLength(32) +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 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 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: !empty(description) ? description : null + displayName: !empty(displayName) ? displayName : null + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: !empty(expiresOn) ? expiresOn : null + metadata: !empty(metadata) ? metadata : null + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : null + } +} + +@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/ptn/authorization/policy-exemption/modules/resource-group.bicep b/avm/ptn/authorization/policy-exemption/modules/resource-group.bicep new file mode 100644 index 0000000000..43b720e473 --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/modules/resource-group.bicep @@ -0,0 +1,68 @@ +metadata name = 'Policy Exemptions (Resource Group scope)' +metadata description = 'This module deploys a policy exemption at a Resource Group scope.' +metadata owner = 'Azure/module-maintainers' + +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 + +@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(32) +@minLength(32) +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 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 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: !empty(description) ? description : null + displayName: !empty(displayName) ? displayName : null + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: !empty(expiresOn) ? expiresOn : null + metadata: !empty(metadata) ? metadata : null + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : null + } +} + +@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/ptn/authorization/policy-exemption/modules/subscription.bicep b/avm/ptn/authorization/policy-exemption/modules/subscription.bicep new file mode 100644 index 0000000000..7e74aa426d --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/modules/subscription.bicep @@ -0,0 +1,68 @@ +metadata name = 'Policy Exemptions (Subscription scope)' +metadata description = 'This module deploys a policy exemption at a Subscription scope.' +metadata owner = 'Azure/module-maintainers' + +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 + +@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(32) +@minLength(32) +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 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 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: !empty(description) ? description : null + displayName: !empty(displayName) ? displayName : null + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: !empty(expiresOn) ? expiresOn : null + metadata: !empty(metadata) ? metadata : null + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : null + } +} + +@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/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..56af9ab567 --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +// ========== // +// 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}---${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = 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 = 'apedef' + +@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 + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..295de7aabe --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +// ========== // +// 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}---${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = 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 = 'apewaf' + +@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 + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/ptn/authorization/policy-exemption/version.json b/avm/ptn/authorization/policy-exemption/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/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" + ] +} From f1f12dc3329f8e7510bb51bef254b1a4a83489d8 Mon Sep 17 00:00:00 2001 From: Jack Tracey <41163455+jtracey93@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:53:08 +0100 Subject: [PATCH 41/93] fix: for #3443 `lz/sub-vending` (#3491) ## Description This pull request introduces a new parameter `managementGroupAssociationDelayCount` to the `sub-vending` module, which adds a delay to the subscription being moved to the target management group. This delay is intended to allow for background platform RBAC inheritance to occur. The changes span multiple files, including updates to `README.md`, `main.bicep`, `main.json`, and `subResourceWrapper.bicep`. Fixes #3443 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.lz.sub-vending](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml/badge.svg?branch=main)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml)| ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/lz/sub-vending/README.md | 9 ++ avm/ptn/lz/sub-vending/main.bicep | 4 + avm/ptn/lz/sub-vending/main.json | 50 +++++- .../modules/subResourceWrapper.bicep | 27 ++++ ...ister-SubscriptionResourceProviderList.ps1 | 144 +++++++++--------- 5 files changed, 158 insertions(+), 76 deletions(-) diff --git a/avm/ptn/lz/sub-vending/README.md b/avm/ptn/lz/sub-vending/README.md index de4ec1a5d2..c5abe03e9f 100644 --- a/avm/ptn/lz/sub-vending/README.md +++ b/avm/ptn/lz/sub-vending/README.md @@ -623,6 +623,7 @@ param virtualNetworkResourceGroupName = '' | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`existingSubscriptionId`](#parameter-existingsubscriptionid) | string | An existing subscription ID. Use this when you do not want the module to create a new subscription. But do want to manage the management group membership. A subscription ID should be provided in the example format `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`. | | [`hubNetworkResourceId`](#parameter-hubnetworkresourceid) | string | The resource ID of the Virtual Network or Virtual WAN Hub in the hub to which the created Virtual Network, by this module, will be peered/connected to via Virtual Network Peering or a Virtual WAN Virtual Hub Connection.

| +| [`managementGroupAssociationDelayCount`](#parameter-managementgroupassociationdelaycount) | int | The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur. | | [`resourceProviders`](#parameter-resourceproviders) | object | An object of resource providers and resource providers features to register. If left blank/empty, no resource providers will be registered.

| | [`roleAssignmentEnabled`](#parameter-roleassignmentenabled) | bool | Whether to create role assignments or not. If true, supply the array of role assignment objects in the parameter called `roleAssignments`.

| | [`roleAssignments`](#parameter-roleassignments) | array | Supply an array of objects containing the details of the role assignments to create.

Each object must contain the following `keys`:

  • `principalId` = The Object ID of the User, Group, SPN, Managed Identity to assign the RBAC role too.
  • `definition` = The Name of one of the pre-defined built-In RBAC Roles or a Resource ID of a Built-in or custom RBAC Role Definition as follows:

    - You can only provide the RBAC role name of the pre-defined roles (Contributor, Owner, Reader, Role Based Access Control Administrator (Preview), and User Access Administrator). We only provide those roles as they are the most common ones to assign to a new subscription, also to reduce the template size and complexity in case we define each and every Built-in RBAC role.

    - You can provide the Resource ID of a Built-in or custom RBAC Role Definition

    - e.g. `/providers/Microsoft.Authorization/roleDefinitions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`

  • `relativeScope` = 2 options can be provided for input value:

    1. `''` *(empty string)* = Make RBAC Role Assignment to Subscription scope

    2. `'/resourceGroups/'` = Make RBAC Role Assignment to specified Resource Group.

    | @@ -735,6 +736,14 @@ The resource ID of the Virtual Network or Virtual WAN Hub in the hub to which th - Type: string - Default: `''` +### Parameter: `managementGroupAssociationDelayCount` + +The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur. + +- Required: No +- Type: int +- Default: `15` + ### Parameter: `resourceProviders` An object of resource providers and resource providers features to register. If left blank/empty, no resource providers will be registered.

    diff --git a/avm/ptn/lz/sub-vending/main.bicep b/avm/ptn/lz/sub-vending/main.bicep index dd26bc28a1..62f27ca2c3 100644 --- a/avm/ptn/lz/sub-vending/main.bicep +++ b/avm/ptn/lz/sub-vending/main.bicep @@ -297,6 +297,9 @@ param resourceProviders object = { 'Microsoft.Web': [] } +@sys.description('Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur.') +param managementGroupAssociationDelayCount int = 15 + // VARIABLES var existingSubscriptionIDEmptyCheck = empty(existingSubscriptionId) @@ -355,6 +358,7 @@ module createSubscriptionResources './modules/subResourceWrapper.bicep' = if (su subscriptionId: (subscriptionAliasEnabled && empty(existingSubscriptionId)) ? createSubscription.outputs.subscriptionId : existingSubscriptionId + managementGroupAssociationDelayCount: managementGroupAssociationDelayCount subscriptionManagementGroupAssociationEnabled: subscriptionManagementGroupAssociationEnabled subscriptionManagementGroupId: subscriptionManagementGroupId subscriptionTags: subscriptionTags diff --git a/avm/ptn/lz/sub-vending/main.json b/avm/ptn/lz/sub-vending/main.json index e42574e3c1..ee24f61ead 100644 --- a/avm/ptn/lz/sub-vending/main.json +++ b/avm/ptn/lz/sub-vending/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "2343164809013150587" + "templateHash": "2644636658214532574" }, "name": "Sub-vending", "description": "This module deploys a subscription to accelerate deployment of landing zones. For more information on how to use it, please visit this [Wiki](https://github.com/Azure/bicep-lz-vending/wiki).", @@ -377,6 +377,13 @@ "metadata": { "description": "Optional. An object of resource providers and resource providers features to register. If left blank/empty, no resource providers will be registered.\n" } + }, + "managementGroupAssociationDelayCount": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur." + } } }, "variables": { @@ -546,6 +553,9 @@ "mode": "Incremental", "parameters": { "subscriptionId": "[if(and(parameters('subscriptionAliasEnabled'), empty(parameters('existingSubscriptionId'))), createObject('value', reference(extensionResourceId(managementGroup().id, 'Microsoft.Resources/deployments', variables('deploymentNames').createSubscription), '2022-09-01').outputs.subscriptionId.value), createObject('value', parameters('existingSubscriptionId')))]", + "managementGroupAssociationDelayCount": { + "value": "[parameters('managementGroupAssociationDelayCount')]" + }, "subscriptionManagementGroupAssociationEnabled": { "value": "[parameters('subscriptionManagementGroupAssociationEnabled')]" }, @@ -653,7 +663,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "12288692280280036332" + "templateHash": "2549730186599602050" }, "name": "`/subResourcesWrapper/deploy.bicep` Parameters", "description": "This module is used by the [`bicep-lz-vending`](https://aka.ms/sub-vending/bicep) module to help orchestrate the deployment", @@ -960,11 +970,19 @@ "metadata": { "description": "The name of the storage account for the deployment script." } + }, + "managementGroupAssociationDelayCount": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur." + } } }, "variables": { - "$fxv#0": "Param(\n[string]$subscriptionId,\n[string]$resourceProviders\n)\n\n$ErrorActionPreference = 'SilentlyContinue'\n# Selecting the right subscription\nSelect-AzSubscription -SubscriptionId $subscriptionId\n\n# Defining variables\n$providers = $resourceProviders | ConvertFrom-Json -AsHashtable\n$failedProviders = ''\n$failedFeatures = ''\n$DeploymentScriptOutputs = @{}\n\n##############################################\n## Registering resource providers and features\n##############################################\n\nif ($providers.Count -gt 0) {\n foreach ($provider in $providers.keys) {\n try {\n # Registering resource providers\n $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState\n # Check if the providered is registered\n if ($providerStatus -eq 'NotRegistered') {\n Write-Output \"`n Registering the '$provider' provider\"\n if (Register-AzResourceProvider -ProviderNamespace $provider) {\n Write-Output \"`n The registration for provider'$provider' has started successfully\"\n } else {\n Write-Output \"`n The '$provider' provider has not been registered successfully\"\n $failedProviders += \",$provider\"\n }\n } elseif ($providerStatus -eq 'Registering') {\n Write-Output \"`n The '$provider' provider is in registering state\"\n $failedProviders += \",$provider\"\n } elseif ( $null -eq $providerStatus) {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n }\n\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n }\n # Registering resource providers features\n $features = $providers[$provider]\n if ($features.length -gt 0) {\n foreach ($feature in $features) {\n try {\n # Define variables\n $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState\n # Check if the feature is registered\n if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') {\n Write-Output \"`n Registering the '$feature' feature\"\n if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) {\n Write-Output \"`n The The registration for feature '$feature' has started successfully\"\n } else {\n Write-Output \"`n The '$feature' feature has not been registered successfully\"\n $failedFeatures += \",$feature\"\n }\n } elseif ($null -eq $featureStatus) {\n Write-Output \"`n The '$feature' feature doesn't exist.\"\n $failedFeatures += \",$feature\"\n }\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid\"\n $failedFeatures += \",$feature\"\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n } else {\n $output = 'No failures'\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n} else {\n Write-Output \"`n No providers or features to register\"\n}\n", + "$fxv#0": "Param(\n [string]$subscriptionId,\n [string]$resourceProviders\n)\n\n$ErrorActionPreference = 'SilentlyContinue'\n# Selecting the right subscription\nSelect-AzSubscription -SubscriptionId $subscriptionId\n\n# Defining variables\n$providers = $resourceProviders | ConvertFrom-Json -AsHashtable\n$failedProviders = ''\n$failedFeatures = ''\n$DeploymentScriptOutputs = @{}\n\n##############################################\n## Registering resource providers and features\n##############################################\n\nif ($providers.Count -gt 0) {\n foreach ($provider in $providers.keys) {\n try {\n # Registering resource providers\n $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState\n # Check if the providered is registered\n if ($providerStatus -eq 'NotRegistered') {\n Write-Output \"`n Registering the '$provider' provider\"\n if (Register-AzResourceProvider -ProviderNamespace $provider) {\n Write-Output \"`n The registration for provider'$provider' has started successfully\"\n } else {\n Write-Output \"`n The '$provider' provider has not been registered successfully\"\n $failedProviders += \",$provider\"\n }\n } elseif ($providerStatus -eq 'Registering') {\n Write-Output \"`n The '$provider' provider is in registering state\"\n $failedProviders += \",$provider\"\n } elseif ( $null -eq $providerStatus) {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n }\n\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n }\n # Registering resource providers features\n $features = $providers[$provider]\n if ($features.length -gt 0) {\n foreach ($feature in $features) {\n try {\n # Define variables\n $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState\n # Check if the feature is registered\n if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') {\n Write-Output \"`n Registering the '$feature' feature\"\n if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) {\n Write-Output \"`n The The registration for feature '$feature' has started successfully\"\n } else {\n Write-Output \"`n The '$feature' feature has not been registered successfully\"\n $failedFeatures += \",$feature\"\n }\n } elseif ($null -eq $featureStatus) {\n Write-Output \"`n The '$feature' feature doesn't exist.\"\n $failedFeatures += \",$feature\"\n }\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid\"\n $failedFeatures += \",$feature\"\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n } else {\n $output = 'No failures'\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n} else {\n Write-Output \"`n No providers or features to register\"\n}\n", "deploymentNames": { + "moveSubscriptionToManagementGroupDelay": "[take(format('lz-vend-move-sub-delay-{0}', uniqueString(parameters('subscriptionId'), parameters('subscriptionManagementGroupId'), deployment().name)), 64)]", "moveSubscriptionToManagementGroup": "[take(format('lz-vend-move-sub-{0}', uniqueString(parameters('subscriptionId'), parameters('subscriptionManagementGroupId'), deployment().name)), 64)]", "tagSubscription": "[take(format('lz-vend-tag-sub-{0}', uniqueString(parameters('subscriptionId'), deployment().name)), 64)]", "createResourceGroupForLzNetworking": "[take(format('lz-vend-rsg-create-{0}', uniqueString(parameters('subscriptionId'), parameters('virtualNetworkResourceGroupName'), parameters('virtualNetworkLocation'), deployment().name)), 64)]", @@ -1002,6 +1020,27 @@ "resourceProvidersFormatted": "[replace(string(parameters('resourceProviders')), '\"', '\\\"')]" }, "resources": [ + { + "copy": { + "name": "moveSubscriptionToManagementGroupDelay", + "count": "[length(range(0, parameters('managementGroupAssociationDelayCount')))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[and(parameters('subscriptionManagementGroupAssociationEnabled'), not(empty(parameters('subscriptionManagementGroupId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('{0}-{1}', variables('deploymentNames').moveSubscriptionToManagementGroupDelay, copyIndex())]", + "location": "[parameters('virtualNetworkLocation')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + }, { "condition": "[and(parameters('subscriptionManagementGroupAssociationEnabled'), not(empty(parameters('subscriptionManagementGroupId'))))]", "type": "Microsoft.Resources/deployments", @@ -1055,7 +1094,10 @@ } ] } - } + }, + "dependsOn": [ + "moveSubscriptionToManagementGroupDelay" + ] }, { "condition": "[not(empty(parameters('subscriptionTags')))]", diff --git a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep index ab9684a5a6..d0b80795eb 100644 --- a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep +++ b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep @@ -188,11 +188,18 @@ param deploymentScriptManagedIdentityName string @sys.description('The name of the storage account for the deployment script.') param deploymentScriptStorageAccountName string +@sys.description('Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur.') +param managementGroupAssociationDelayCount int = 15 + // VARIABLES // Deployment name variables // LIMITS: Tenant = 64, Management Group = 64, Subscription = 64, Resource Group = 64 var deploymentNames = { + moveSubscriptionToManagementGroupDelay: take( + 'lz-vend-move-sub-delay-${uniqueString(subscriptionId, subscriptionManagementGroupId, deployment().name)}', + 64 + ) moveSubscriptionToManagementGroup: take( 'lz-vend-move-sub-${uniqueString(subscriptionId, subscriptionManagementGroupId, deployment().name)}', 64 @@ -313,8 +320,28 @@ var resourceProvidersFormatted = replace(string(resourceProviders), '"', '\\"') // RESOURCES & MODULES +@batchSize(1) +#disable-next-line no-deployments-resources +resource moveSubscriptionToManagementGroupDelay 'Microsoft.Resources/deployments@2024-03-01' = [ + for (cycle, i) in range(0, managementGroupAssociationDelayCount): if (subscriptionManagementGroupAssociationEnabled && !empty(subscriptionManagementGroupId)) { + name: '${deploymentNames.moveSubscriptionToManagementGroupDelay}-${i}' + location: virtualNetworkLocation + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } + } +] + module moveSubscriptionToManagementGroup './managementGroupSubscription.bicep' = if (subscriptionManagementGroupAssociationEnabled && !empty(subscriptionManagementGroupId)) { scope: managementGroup(subscriptionManagementGroupId) + dependsOn: [ + moveSubscriptionToManagementGroupDelay + ] name: deploymentNames.moveSubscriptionToManagementGroup params: { subscriptionManagementGroupId: subscriptionManagementGroupId diff --git a/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 b/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 index 3bbc201cf5..57396617c6 100644 --- a/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 +++ b/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 @@ -1,6 +1,6 @@ Param( -[string]$subscriptionId, -[string]$resourceProviders + [string]$subscriptionId, + [string]$resourceProviders ) $ErrorActionPreference = 'SilentlyContinue' @@ -18,81 +18,81 @@ $DeploymentScriptOutputs = @{} ############################################## if ($providers.Count -gt 0) { - foreach ($provider in $providers.keys) { - try { - # Registering resource providers - $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState - # Check if the providered is registered - if ($providerStatus -eq 'NotRegistered') { - Write-Output "`n Registering the '$provider' provider" - if (Register-AzResourceProvider -ProviderNamespace $provider) { - Write-Output "`n The registration for provider'$provider' has started successfully" - } else { - Write-Output "`n The '$provider' provider has not been registered successfully" - $failedProviders += ",$provider" - } - } elseif ($providerStatus -eq 'Registering') { - Write-Output "`n The '$provider' provider is in registering state" - $failedProviders += ",$provider" - } elseif ( $null -eq $providerStatus) { - Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" - $failedProviders += ",$provider" - } - - if ($failedProviders.length -gt 0) { - $output = $failedProviders.substring(1) - } else { - $output = 'No failures' - } - $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output - } catch { - Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" - $failedProviders += ",$provider" - if ($failedProviders.length -gt 0) { - $output = $failedProviders.substring(1) - } - $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output - } - # Registering resource providers features - $features = $providers[$provider] - if ($features.length -gt 0) { - foreach ($feature in $features) { + foreach ($provider in $providers.keys) { try { - # Define variables - $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState - # Check if the feature is registered - if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') { - Write-Output "`n Registering the '$feature' feature" - if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) { - Write-Output "`n The The registration for feature '$feature' has started successfully" + # Registering resource providers + $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState + # Check if the providered is registered + if ($providerStatus -eq 'NotRegistered') { + Write-Output "`n Registering the '$provider' provider" + if (Register-AzResourceProvider -ProviderNamespace $provider) { + Write-Output "`n The registration for provider'$provider' has started successfully" + } else { + Write-Output "`n The '$provider' provider has not been registered successfully" + $failedProviders += ",$provider" + } + } elseif ($providerStatus -eq 'Registering') { + Write-Output "`n The '$provider' provider is in registering state" + $failedProviders += ",$provider" + } elseif ( $null -eq $providerStatus) { + Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" + $failedProviders += ",$provider" + } + + if ($failedProviders.length -gt 0) { + $output = $failedProviders.substring(1) } else { - Write-Output "`n The '$feature' feature has not been registered successfully" - $failedFeatures += ",$feature" + $output = 'No failures' } - } elseif ($null -eq $featureStatus) { - Write-Output "`n The '$feature' feature doesn't exist." - $failedFeatures += ",$feature" - } - if ($failedFeatures.length -gt 0) { - $output = $failedFeatures.substring(1) - } else { - $output = 'No failures' - } - $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output } catch { - Write-Output "`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid" - $failedFeatures += ",$feature" - if ($failedFeatures.length -gt 0) { - $output = $failedFeatures.substring(1) - } - $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" + $failedProviders += ",$provider" + if ($failedProviders.length -gt 0) { + $output = $failedProviders.substring(1) + } + $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output + } + # Registering resource providers features + $features = $providers[$provider] + if ($features.length -gt 0) { + foreach ($feature in $features) { + try { + # Define variables + $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState + # Check if the feature is registered + if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') { + Write-Output "`n Registering the '$feature' feature" + if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) { + Write-Output "`n The The registration for feature '$feature' has started successfully" + } else { + Write-Output "`n The '$feature' feature has not been registered successfully" + $failedFeatures += ",$feature" + } + } elseif ($null -eq $featureStatus) { + Write-Output "`n The '$feature' feature doesn't exist." + $failedFeatures += ",$feature" + } + if ($failedFeatures.length -gt 0) { + $output = $failedFeatures.substring(1) + } else { + $output = 'No failures' + } + $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + } catch { + Write-Output "`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid" + $failedFeatures += ",$feature" + if ($failedFeatures.length -gt 0) { + $output = $failedFeatures.substring(1) + } + $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + } + } + } else { + $output = 'No failures' + $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output } - } - } else { - $output = 'No failures' - $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output } - } } else { - Write-Output "`n No providers or features to register" + Write-Output "`n No providers or features to register" } From 0857ef4e33ffcfcc11a861abd4ae09d7a52f0067 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:43:55 +0100 Subject: [PATCH 42/93] fix: bump actions/upload-artifact from 4.4.0 to 4.4.2 (#3495) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.4.0 to 4.4.2.

    Release notes

    Sourced from actions/upload-artifact's releases.

    v4.4.2

    What's Changed

    Full Changelog: https://github.com/actions/upload-artifact/compare/v4...v4.4.2

    v4.4.1

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/upload-artifact/compare/v4.4.0...v4.4.1

    Commits
    • 8448086 Merge pull request #627 from actions/robherley/v4.4.2
    • b1d4642 add explicit relative and absolute symlinks to workflow
    • d50e660 bump version
    • aabe6f8 build with @​actions/artifact v2.1.11
    • 604373d Merge pull request #625 from actions/robherley/artifact-2.1.10
    • 0150148 paste right core version
    • a009b25 update licenses
    • 9f6f6f4 update @​actions/core and @​actions/artifact to latest versions
    • 3eadd8b Merge pull request #621 from actions/Jcambass-patch-1
    • aeba9f7 Add workflow file for publishing releases to immutable action package
    • Additional commits viewable in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=4.4.0&new-version=4.4.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/platform.ossf-scorecard.yml | 2 +- .github/workflows/platform.publish-module-index-json.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/platform.ossf-scorecard.yml b/.github/workflows/platform.ossf-scorecard.yml index cfbec6ff1f..54b28dad6a 100644 --- a/.github/workflows/platform.ossf-scorecard.yml +++ b/.github/workflows/platform.ossf-scorecard.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/platform.publish-module-index-json.yml b/.github/workflows/platform.publish-module-index-json.yml index 9c140c7102..2d2d3eac69 100644 --- a/.github/workflows/platform.publish-module-index-json.yml +++ b/.github/workflows/platform.publish-module-index-json.yml @@ -74,7 +74,7 @@ jobs: } - name: Upload artifacts - uses: actions/upload-artifact@v4.4.0 + uses: actions/upload-artifact@v4.4.2 with: name: publish-module-index-json-artifacts path: | From 8d0d18f7029ed623caeb2d31e31f4f980162cbf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:46:04 +0100 Subject: [PATCH 43/93] fix: bump github/codeql-action from 3.26.9 to 3.26.12 (#3455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.9 to 3.26.12.
    Changelog

    Sourced from github/codeql-action's changelog.

    CodeQL Action Changelog

    See the releases page for the relevant changes to the CodeQL CLI and language packs.

    Note that the only difference between v2 and v3 of the CodeQL Action is the node version they support, with v3 running on node 20 while we continue to release v2 to support running on node 16. For example 3.22.11 was the first v3 release and is functionally identical to 2.22.11. This approach ensures an easy way to track exactly which features are included in different versions, indicated by the minor and patch version numbers.

    [UNRELEASED]

    No user facing changes.

    3.26.12 - 07 Oct 2024

    • Upcoming breaking change: Add a deprecation warning for customers using CodeQL version 2.14.5 and earlier. These versions of CodeQL were discontinued on 24 September 2024 alongside GitHub Enterprise Server 3.10, and will be unsupported by CodeQL Action versions 3.27.0 and later and versions 2.27.0 and later. #2520

      • If you are using one of these versions, please update to CodeQL CLI version 2.14.6 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.

      • Alternatively, if you want to continue using a version of the CodeQL CLI between 2.13.5 and 2.14.5, you can replace github/codeql-action/*@v3 by github/codeql-action/*@v3.26.11 and github/codeql-action/*@v2 by github/codeql-action/*@v2.26.11 in your code scanning workflow to ensure you continue using this version of the CodeQL Action.

    3.26.11 - 03 Oct 2024

    • Upcoming breaking change: Add support for using actions/download-artifact@v4 to programmatically consume CodeQL Action debug artifacts.

      Starting November 30, 2024, GitHub.com customers will no longer be able to use actions/download-artifact@v3. Therefore, to avoid breakage, customers who programmatically download the CodeQL Action debug artifacts should set the CODEQL_ACTION_ARTIFACT_V4_UPGRADE environment variable to true and bump actions/download-artifact@v3 to actions/download-artifact@v4 in their workflows. The CodeQL Action will enable this behavior by default in early November and workflows that have not yet bumped to actions/download-artifact@v3 to actions/download-artifact@v4 will begin failing then.

      This change is currently unavailable for GitHub Enterprise Server customers, as actions/upload-artifact@v4 and actions/download-artifact@v4 are not yet compatible with GHES.

    • Update default CodeQL bundle version to 2.19.1. #2519

    3.26.10 - 30 Sep 2024

    • We are rolling out a feature in September/October 2024 that sets up CodeQL using a bundle compressed with Zstandard. Our aim is to improve the performance of setting up CodeQL. #2502

    3.26.9 - 24 Sep 2024

    No user facing changes.

    3.26.8 - 19 Sep 2024

    • Update default CodeQL bundle version to 2.19.0. #2483

    3.26.7 - 13 Sep 2024

    • Update default CodeQL bundle version to 2.18.4. #2471

    3.26.6 - 29 Aug 2024

    • Update default CodeQL bundle version to 2.18.3. #2449

    3.26.5 - 23 Aug 2024

    • Fix an issue where the csrutil system call used for telemetry would fail on MacOS ARM machines with System Integrity Protection disabled. #2441

    ... (truncated)

    Commits
    • c36620d Merge pull request #2529 from github/update-v3.26.12-c9a70ff45
    • 570aecb Update changelog for v3.26.12
    • c9a70ff Merge pull request #2526 from github/henrymercer/check-zstd-on-path
    • d65a176 Rebuild
    • bf2e624 Update src/tar.ts
    • 56d1975 Merge pull request #2489 from github/redsun82/rust
    • 7cf65a5 Merge pull request #2518 from github/dependabot/npm_and_yarn/npm-88156698cd
    • 8a56dd2 Update to @​actions/core 1.11.1
    • 1532671 Update default bundle to 2.19.1 (#2519)
    • 64871a8 Merge branch 'main' into update-bundle/codeql-bundle-v2.19.1
    • Additional commits viewable in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=3.26.9&new-version=3.26.12)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/platform.ossf-scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/platform.ossf-scorecard.yml b/.github/workflows/platform.ossf-scorecard.yml index 54b28dad6a..b6f8d9fa50 100644 --- a/.github/workflows/platform.ossf-scorecard.yml +++ b/.github/workflows/platform.ossf-scorecard.yml @@ -68,6 +68,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 + uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: sarif_file: results.sarif From 11aba421d9d824b9dc8ff5195e9f5e8688e775ce Mon Sep 17 00:00:00 2001 From: Collin Mezach Date: Wed, 9 Oct 2024 16:45:53 +0200 Subject: [PATCH 44/93] feat: `avm/res/Cdn/profile` Add managed identity (#3446) ## Add managed identity to CDN module This is my first contribution, i hope i'm doing it right :) - added functionality to enable a system-assigned managed identity or a user-assigned managed identity for the CDN Profile module. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cdn.profile](https://github.com/cmezach/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg)](https://github.com/cmezach/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Collin Mezach --- avm/res/cdn/profile/README.md | 41 ++++++++++++++++++ avm/res/cdn/profile/main.bicep | 30 +++++++++++++ avm/res/cdn/profile/main.json | 43 ++++++++++++++++++- .../cdn/profile/tests/e2e/afd/main.test.bicep | 3 ++ avm/res/cdn/profile/version.json | 2 +- 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index 0bd698095d..cdbbe70b4d 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -420,6 +420,9 @@ module profile 'br/public:avm/res/cdn/profile:' = { } ] location: 'global' + managedIdentities: { + systemAssigned: true + } originGroups: [ { loadBalancingSettings: { @@ -517,6 +520,11 @@ module profile 'br/public:avm/res/cdn/profile:' = { "location": { "value": "global" }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "originGroups": { "value": [ { @@ -608,6 +616,9 @@ param customDomains = [ } ] param location = 'global' +param managedIdentities = { + systemAssigned: true +} param originGroups = [ { loadBalancingSettings: { @@ -1153,6 +1164,7 @@ param originResponseTimeoutSeconds = 60 | [`endpointProperties`](#parameter-endpointproperties) | object | Endpoint properties (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/endpoints?pivots=deployment-language-bicep#endpointproperties for details). | | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`originResponseTimeoutSeconds`](#parameter-originresponsetimeoutseconds) | int | Send and receive timeout on forwarding request to the origin. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ruleSets`](#parameter-rulesets) | array | Array of rule set objects. | @@ -1281,6 +1293,34 @@ Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + ### Parameter: `originResponseTimeoutSeconds` Send and receive timeout on forwarding request to the origin. @@ -1501,6 +1541,7 @@ Endpoint tags. | `profileType` | string | The type of the CDN profile. | | `resourceGroupName` | string | The resource group where the CDN profile is deployed. | | `resourceId` | string | The resource ID of the CDN profile. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | | `uri` | string | The uri of the CDN profile endpoint. | ## Data Collection diff --git a/avm/res/cdn/profile/main.bicep b/avm/res/cdn/profile/main.bicep index 87323ba79f..2c30c0c2e2 100644 --- a/avm/res/cdn/profile/main.bicep +++ b/avm/res/cdn/profile/main.bicep @@ -55,6 +55,9 @@ param securityPolicies securityPolicyType = [] @description('Optional. Endpoint tags.') param tags object? +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + @description('Optional. The lock settings of the service.') param lock lockType @@ -105,6 +108,21 @@ var formattedRoleAssignments = [ }) ] +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { name: '46d3xbcp.res.cdn-profile.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' @@ -127,6 +145,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT resource profile 'Microsoft.Cdn/profiles@2023-05-01' = { name: name location: location + identity: identity sku: { name: sku } @@ -294,10 +313,21 @@ output endpointId string = !empty(endpointProperties) ? profile_endpoint.outputs @description('The uri of the CDN profile endpoint.') output uri string = !empty(endpointProperties) ? profile_endpoint.outputs.uri : '' +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = profile.?identity.?principalId ?? '' + // =============== // // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + import { associationsType } from 'securityPolicies/main.bicep' type securityPolicyType = { @description('Required. Name of the security policy.') diff --git a/avm/res/cdn/profile/main.json b/avm/res/cdn/profile/main.json index 169cee8564..479e17ece5 100644 --- a/avm/res/cdn/profile/main.json +++ b/avm/res/cdn/profile/main.json @@ -6,13 +6,36 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "18013902785904421717" + "templateHash": "14447016685732236984" }, "name": "CDN Profiles", "description": "This module deploys a CDN Profile.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, "securityPolicyType": { "type": "array", "items": { @@ -281,6 +304,12 @@ "description": "Optional. Endpoint tags." } }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "lock": { "$ref": "#/definitions/lockType", "metadata": { @@ -319,7 +348,9 @@ "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, "resources": { "avmTelemetry": { @@ -347,6 +378,7 @@ "apiVersion": "2023-05-01", "name": "[parameters('name')]", "location": "[parameters('location')]", + "identity": "[variables('identity')]", "sku": { "name": "[parameters('sku')]" }, @@ -2411,6 +2443,13 @@ "description": "The uri of the CDN profile endpoint." }, "value": "[if(not(empty(parameters('endpointProperties'))), reference('profile_endpoint').outputs.uri.value, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('profile', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" } } } \ No newline at end of file diff --git a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep index 7fe9142055..66c9abbdfb 100644 --- a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep +++ b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep @@ -42,6 +42,9 @@ module testDeployment '../../../main.bicep' = [ name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { name: 'dep-${namePrefix}-test-${serviceShort}' + managedIdentities: { + systemAssigned: true + } location: 'global' originResponseTimeoutSeconds: 60 sku: 'Standard_AzureFrontDoor' diff --git a/avm/res/cdn/profile/version.json b/avm/res/cdn/profile/version.json index 9ed3662aba..35040975ae 100644 --- a/avm/res/cdn/profile/version.json +++ b/avm/res/cdn/profile/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.6", + "version": "0.7", "pathFilters": [ "./main.json" ] From 20d2fb16baaba0fc0963f2eb98efd47dead714d7 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Wed, 9 Oct 2024 18:03:06 +0200 Subject: [PATCH 45/93] fix: Removed misplaced pipeline triggers for 2 pattern modules (#3396) ## Description Removed misplaced pipeline triggers for 2 pattern modules ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- .github/workflows/avm.ptn.aca-lza.hosting-environment.yml | 1 - .github/workflows/avm.res.network.application-gateway.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml b/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml index d7f47a87e5..aed8ec0c1e 100644 --- a/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml +++ b/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml @@ -26,7 +26,6 @@ on: push: branches: - main - - avm-ptn-acalza-hostingenvironment paths: - ".github/actions/templates/avm-**" - ".github/workflows/avm.template.module.yml" diff --git a/.github/workflows/avm.res.network.application-gateway.yml b/.github/workflows/avm.res.network.application-gateway.yml index 2439e1ab16..095cf15ade 100644 --- a/.github/workflows/avm.res.network.application-gateway.yml +++ b/.github/workflows/avm.res.network.application-gateway.yml @@ -25,7 +25,6 @@ on: push: branches: - main - - avm-application-gateway paths: - ".github/actions/templates/avm-**" - ".github/workflows/avm.template.module.yml" From 156e95ce91c0faf59357d12a3713bca47a1f333d Mon Sep 17 00:00:00 2001 From: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:28:30 +0200 Subject: [PATCH 46/93] feat: Update VM (use existing PIP) (#3336) closes #2702 An existing PIP can be provided. run (except NVidia): [![avm.res.compute.virtual-machine](https://github.com/rahalan/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml/badge.svg)](https://github.com/rahalan/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml) --- avm/res/compute/virtual-machine/README.md | 101 +++-- avm/res/compute/virtual-machine/main.bicep | 196 +++------ avm/res/compute/virtual-machine/main.json | 372 ++++++++++++------ .../modules/nic-configuration.bicep | 87 ++-- .../tests/e2e/atmg/main.test.bicep | 16 +- .../tests/e2e/linux.defaults/main.test.bicep | 17 +- .../tests/e2e/linux.max/dependencies.bicep | 2 +- .../tests/e2e/linux.max/main.test.bicep | 21 +- .../tests/e2e/waf-aligned/dependencies.bicep | 2 +- .../tests/e2e/waf-aligned/main.test.bicep | 21 +- .../e2e/windows.defaults/main.test.bicep | 17 +- .../main.test.bicep | 21 +- .../e2e/windows.hostpool/main.test.bicep | 15 +- .../tests/e2e/windows.max/dependencies.bicep | 19 +- .../tests/e2e/windows.max/main.test.bicep | 29 +- .../tests/e2e/windows.nvidia/main.test.bicep | 7 +- .../tests/e2e/windows.ssecmk/main.test.bicep | 17 +- .../tests/e2e/windows.vmss/main.test.bicep | 17 +- avm/res/compute/virtual-machine/version.json | 2 +- 19 files changed, 509 insertions(+), 470 deletions(-) diff --git a/avm/res/compute/virtual-machine/README.md b/avm/res/compute/virtual-machine/README.md index 42808cbe63..16a4e92bf0 100644 --- a/avm/res/compute/virtual-machine/README.md +++ b/avm/res/compute/virtual-machine/README.md @@ -19,7 +19,7 @@ This module deploys a Virtual Machine with one or multiple NICs and optionally o | `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.Compute/virtualMachines` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-01/virtualMachines) | +| `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) | @@ -98,7 +98,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters configurationProfile: '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' @@ -174,7 +174,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Linux" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -246,7 +246,7 @@ param osDisk = { } } param osType = 'Linux' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 0 // Non-required parameters param configurationProfile = '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' @@ -307,7 +307,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters disablePasswordAuthentication: true @@ -378,7 +378,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Linux" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -443,7 +443,7 @@ param osDisk = { } } param osType = 'Linux' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 0 // Non-required parameters param disablePasswordAuthentication = true @@ -586,7 +586,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { name: 'osdisk01' } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 1 // Non-required parameters backupPolicyName: '' @@ -886,7 +886,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Linux" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 1 @@ -1222,7 +1222,7 @@ param osDisk = { name: 'osdisk01' } param osType = 'Linux' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 1 // Non-required parameters param backupPolicyName = '' @@ -1488,7 +1488,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 2 // Non-required parameters adminPassword: '' @@ -1780,7 +1780,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 2 @@ -2112,7 +2112,7 @@ param osDisk = { } } param osType = 'Windows' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 2 // Non-required parameters param adminPassword = '' @@ -2330,7 +2330,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -2392,7 +2392,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -2446,7 +2446,7 @@ param osDisk = { } } param osType = 'Windows' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 0 // Non-required parameters param adminPassword = '' @@ -2483,6 +2483,10 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { ipConfigurations: [ { name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } subnetResourceId: '' } ] @@ -2497,7 +2501,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -2568,6 +2572,10 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "ipConfigurations": [ { "name": "ipconfig01", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-01", + "zones": [] + }, "subnetResourceId": "" } ], @@ -2588,7 +2596,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -2663,6 +2671,10 @@ param nicConfigurations = [ ipConfigurations: [ { name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } subnetResourceId: '' } ] @@ -2677,7 +2689,7 @@ param osDisk = { } } param osType = 'Windows' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 0 // Non-required parameters param adminPassword = '' @@ -2757,7 +2769,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -2842,7 +2854,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -2925,7 +2937,7 @@ param osDisk = { } } param osType = 'Windows' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 0 // Non-required parameters param adminPassword = '' @@ -3026,7 +3038,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { ] name: 'ipconfig01' pipConfiguration: { - publicIpNameSuffix: '-pip-01' + publicIPAddressResourceId: '' roleAssignments: [ { name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' @@ -3045,11 +3057,6 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { roleDefinitionIdOrName: '' } ] - zones: [ - 1 - 2 - 3 - ] } subnetResourceId: '' } @@ -3086,7 +3093,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { name: 'osdisk01' } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 2 // Non-required parameters adminPassword: '' @@ -3350,7 +3357,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { ], "name": "ipconfig01", "pipConfiguration": { - "publicIpNameSuffix": "-pip-01", + "publicIPAddressResourceId": "", "roleAssignments": [ { "name": "e962e7c1-261a-4afd-b5ad-17a640a0b7bc", @@ -3368,11 +3375,6 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "principalType": "ServicePrincipal", "roleDefinitionIdOrName": "" } - ], - "zones": [ - 1, - 2, - 3 ] }, "subnetResourceId": "" @@ -3416,7 +3418,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 2 @@ -3726,7 +3728,7 @@ param nicConfigurations = [ ] name: 'ipconfig01' pipConfiguration: { - publicIpNameSuffix: '-pip-01' + publicIPAddressResourceId: '' roleAssignments: [ { name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' @@ -3745,11 +3747,6 @@ param nicConfigurations = [ roleDefinitionIdOrName: '' } ] - zones: [ - 1 - 2 - 3 - ] } subnetResourceId: '' } @@ -3786,7 +3783,7 @@ param osDisk = { name: 'osdisk01' } param osType = 'Windows' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 2 // Non-required parameters param adminPassword = '' @@ -4198,7 +4195,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -4273,7 +4270,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -4342,7 +4339,7 @@ param osDisk = { } } param osType = 'Windows' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 0 // Non-required parameters param adminPassword = '' @@ -4404,7 +4401,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -4467,7 +4464,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -4524,7 +4521,7 @@ param osDisk = { } } param osType = 'Windows' -param vmSize = 'Standard_DS2_v2' +param vmSize = 'Standard_D2s_v3' param zone = 0 // Non-required parameters param adminPassword = '' @@ -5746,11 +5743,13 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/network-interface:0.2.4` | Remote reference | -| `br/public:avm/res/network/public-ip-address:0.4.1` | Remote reference | +| `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: diff --git a/avm/res/compute/virtual-machine/main.bicep b/avm/res/compute/virtual-machine/main.bicep index 1b92cfe376..d9f22a1b23 100644 --- a/avm/res/compute/virtual-machine/main.bicep +++ b/avm/res/compute/virtual-machine/main.bicep @@ -478,21 +478,15 @@ module vm_nic 'modules/nic-configuration.bicep' = [ for (nicConfiguration, index) in nicConfigurations: { name: '${uniqueString(deployment().name, location)}-VM-Nic-${index}' params: { - networkInterfaceName: contains(nicConfiguration, 'name') - ? nicConfiguration.name - : '${name}${nicConfiguration.nicSuffix}' + networkInterfaceName: nicConfiguration.?name ?? '${name}${nicConfiguration.?nicSuffix}' virtualMachineName: name location: location - enableIPForwarding: contains(nicConfiguration, 'enableIPForwarding') ? nicConfiguration.enableIPForwarding : false - enableAcceleratedNetworking: contains(nicConfiguration, 'enableAcceleratedNetworking') - ? nicConfiguration.enableAcceleratedNetworking - : true + enableIPForwarding: nicConfiguration.?enableIPForwarding ?? false + enableAcceleratedNetworking: nicConfiguration.?enableAcceleratedNetworking ?? true dnsServers: contains(nicConfiguration, 'dnsServers') ? (!empty(nicConfiguration.dnsServers) ? nicConfiguration.dnsServers : []) : [] - networkSecurityGroupResourceId: contains(nicConfiguration, 'networkSecurityGroupResourceId') - ? nicConfiguration.networkSecurityGroupResourceId - : '' + networkSecurityGroupResourceId: nicConfiguration.?networkSecurityGroupResourceId ?? '' ipConfigurations: nicConfiguration.ipConfigurations lock: nicConfiguration.?lock ?? lock tags: nicConfiguration.?tags ?? tags @@ -503,7 +497,7 @@ module vm_nic 'modules/nic-configuration.bicep' = [ } ] -resource vm 'Microsoft.Compute/virtualMachines@2024-03-01' = { +resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = { name: name location: location identity: identity @@ -573,13 +567,13 @@ resource vm 'Microsoft.Compute/virtualMachines@2024-03-01' = { networkInterfaces: [ for (nicConfiguration, index) in nicConfigurations: { properties: { - deleteOption: contains(nicConfiguration, 'deleteOption') ? nicConfiguration.deleteOption : 'Delete' + 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', - contains(nicConfiguration, 'name') ? nicConfiguration.name : '${name}${nicConfiguration.nicSuffix}' + nicConfiguration.?name ?? '${name}${nicConfiguration.?nicSuffix}' ) } ] @@ -654,28 +648,20 @@ resource vm_autoShutdownConfiguration 'Microsoft.DevTestLab/schedules@2018-09-15 name: 'shutdown-computevm-${vm.name}' location: location properties: { - status: contains(autoShutdownConfig, 'status') ? autoShutdownConfig.status : 'Disabled' + status: autoShutdownConfig.?status ?? 'Disabled' targetResourceId: vm.id taskType: 'ComputeVmShutdownTask' dailyRecurrence: { - time: contains(autoShutdownConfig, 'dailyRecurrenceTime') ? autoShutdownConfig.dailyRecurrenceTime : '19:00' + time: autoShutdownConfig.?dailyRecurrenceTime ?? '19:00' } - timeZoneId: contains(autoShutdownConfig, 'timeZone') ? autoShutdownConfig.timeZone : 'UTC' + timeZoneId: autoShutdownConfig.?timeZone ?? 'UTC' notificationSettings: contains(autoShutdownConfig, 'notificationStatus') ? { - status: contains(autoShutdownConfig, 'notificationStatus') - ? autoShutdownConfig.notificationStatus - : 'Disabled' - emailRecipient: contains(autoShutdownConfig, 'notificationEmail') ? autoShutdownConfig.notificationEmail : '' - notificationLocale: contains(autoShutdownConfig, 'notificationLocale') - ? autoShutdownConfig.notificationLocale - : 'en' - webhookUrl: contains(autoShutdownConfig, 'notificationWebhookUrl') - ? autoShutdownConfig.notificationWebhookUrl - : '' - timeInMinutes: contains(autoShutdownConfig, 'notificationTimeInMinutes') - ? autoShutdownConfig.notificationTimeInMinutes - : 30 + status: autoShutdownConfig.?notificationStatus ?? 'Disabled' + emailRecipient: autoShutdownConfig.?notificationEmail ?? '' + notificationLocale: autoShutdownConfig.?notificationLocale ?? 'en' + webhookUrl: autoShutdownConfig.?notificationWebhookUrl ?? '' + timeInMinutes: autoShutdownConfig.?notificationTimeInMinutes ?? 30 } : null } @@ -689,16 +675,10 @@ module vm_aadJoinExtension 'extension/main.bicep' = if (extensionAadJoinConfig.e location: location publisher: 'Microsoft.Azure.ActiveDirectory' type: osType == 'Windows' ? 'AADLoginForWindows' : 'AADSSHLoginforLinux' - typeHandlerVersion: contains(extensionAadJoinConfig, 'typeHandlerVersion') - ? extensionAadJoinConfig.typeHandlerVersion - : (osType == 'Windows' ? '2.0' : '1.0') - autoUpgradeMinorVersion: contains(extensionAadJoinConfig, 'autoUpgradeMinorVersion') - ? extensionAadJoinConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionAadJoinConfig, 'enableAutomaticUpgrade') - ? extensionAadJoinConfig.enableAutomaticUpgrade - : false - settings: contains(extensionAadJoinConfig, 'settings') ? extensionAadJoinConfig.settings : {} + 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 } @@ -712,15 +692,9 @@ module vm_domainJoinExtension 'extension/main.bicep' = if (contains(extensionDom location: location publisher: 'Microsoft.Compute' type: 'JsonADDomainExtension' - typeHandlerVersion: contains(extensionDomainJoinConfig, 'typeHandlerVersion') - ? extensionDomainJoinConfig.typeHandlerVersion - : '1.3' - autoUpgradeMinorVersion: contains(extensionDomainJoinConfig, 'autoUpgradeMinorVersion') - ? extensionDomainJoinConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionDomainJoinConfig, 'enableAutomaticUpgrade') - ? extensionDomainJoinConfig.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionDomainJoinConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionDomainJoinConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDomainJoinConfig.?enableAutomaticUpgrade ?? false settings: extensionDomainJoinConfig.settings supressFailures: extensionDomainJoinConfig.?supressFailures ?? false tags: extensionDomainJoinConfig.?tags ?? tags @@ -741,15 +715,9 @@ module vm_microsoftAntiMalwareExtension 'extension/main.bicep' = if (extensionAn location: location publisher: 'Microsoft.Azure.Security' type: 'IaaSAntimalware' - typeHandlerVersion: contains(extensionAntiMalwareConfig, 'typeHandlerVersion') - ? extensionAntiMalwareConfig.typeHandlerVersion - : '1.3' - autoUpgradeMinorVersion: contains(extensionAntiMalwareConfig, 'autoUpgradeMinorVersion') - ? extensionAntiMalwareConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionAntiMalwareConfig, 'enableAutomaticUpgrade') - ? extensionAntiMalwareConfig.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionAntiMalwareConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionAntiMalwareConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAntiMalwareConfig.?enableAutomaticUpgrade ?? false settings: extensionAntiMalwareConfig.settings supressFailures: extensionAntiMalwareConfig.?supressFailures ?? false tags: extensionAntiMalwareConfig.?tags ?? tags @@ -799,17 +767,11 @@ module vm_dependencyAgentExtension 'extension/main.bicep' = if (extensionDepende location: location publisher: 'Microsoft.Azure.Monitoring.DependencyAgent' type: osType == 'Windows' ? 'DependencyAgentWindows' : 'DependencyAgentLinux' - typeHandlerVersion: contains(extensionDependencyAgentConfig, 'typeHandlerVersion') - ? extensionDependencyAgentConfig.typeHandlerVersion - : '9.10' - autoUpgradeMinorVersion: contains(extensionDependencyAgentConfig, 'autoUpgradeMinorVersion') - ? extensionDependencyAgentConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionDependencyAgentConfig, 'enableAutomaticUpgrade') - ? extensionDependencyAgentConfig.enableAutomaticUpgrade - : true + typeHandlerVersion: extensionDependencyAgentConfig.?typeHandlerVersion ?? '9.10' + autoUpgradeMinorVersion: extensionDependencyAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDependencyAgentConfig.?enableAutomaticUpgrade ?? true settings: { - enableAMA: contains(extensionDependencyAgentConfig, 'enableAMA') ? extensionDependencyAgentConfig.enableAMA : true + enableAMA: extensionDependencyAgentConfig.?enableAMA ?? true } supressFailures: extensionDependencyAgentConfig.?supressFailures ?? false tags: extensionDependencyAgentConfig.?tags ?? tags @@ -827,15 +789,9 @@ module vm_networkWatcherAgentExtension 'extension/main.bicep' = if (extensionNet location: location publisher: 'Microsoft.Azure.NetworkWatcher' type: osType == 'Windows' ? 'NetworkWatcherAgentWindows' : 'NetworkWatcherAgentLinux' - typeHandlerVersion: contains(extensionNetworkWatcherAgentConfig, 'typeHandlerVersion') - ? extensionNetworkWatcherAgentConfig.typeHandlerVersion - : '1.4' - autoUpgradeMinorVersion: contains(extensionNetworkWatcherAgentConfig, 'autoUpgradeMinorVersion') - ? extensionNetworkWatcherAgentConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionNetworkWatcherAgentConfig, 'enableAutomaticUpgrade') - ? extensionNetworkWatcherAgentConfig.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionNetworkWatcherAgentConfig.?typeHandlerVersion ?? '1.4' + autoUpgradeMinorVersion: extensionNetworkWatcherAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionNetworkWatcherAgentConfig.?enableAutomaticUpgrade ?? false supressFailures: extensionNetworkWatcherAgentConfig.?supressFailures ?? false tags: extensionNetworkWatcherAgentConfig.?tags ?? tags } @@ -852,19 +808,13 @@ module vm_desiredStateConfigurationExtension 'extension/main.bicep' = if (extens location: location publisher: 'Microsoft.Powershell' type: 'DSC' - typeHandlerVersion: contains(extensionDSCConfig, 'typeHandlerVersion') - ? extensionDSCConfig.typeHandlerVersion - : '2.77' - autoUpgradeMinorVersion: contains(extensionDSCConfig, 'autoUpgradeMinorVersion') - ? extensionDSCConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionDSCConfig, 'enableAutomaticUpgrade') - ? extensionDSCConfig.enableAutomaticUpgrade - : false - settings: contains(extensionDSCConfig, 'settings') ? extensionDSCConfig.settings : {} + 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: contains(extensionDSCConfig, 'protectedSettings') ? extensionDSCConfig.protectedSettings : {} + protectedSettings: extensionDSCConfig.?protectedSettings ?? {} } dependsOn: [ vm_networkWatcherAgentExtension @@ -879,15 +829,9 @@ module vm_customScriptExtension 'extension/main.bicep' = if (extensionCustomScri location: location publisher: osType == 'Windows' ? 'Microsoft.Compute' : 'Microsoft.Azure.Extensions' type: osType == 'Windows' ? 'CustomScriptExtension' : 'CustomScript' - typeHandlerVersion: contains(extensionCustomScriptConfig, 'typeHandlerVersion') - ? extensionCustomScriptConfig.typeHandlerVersion - : (osType == 'Windows' ? '1.10' : '2.1') - autoUpgradeMinorVersion: contains(extensionCustomScriptConfig, 'autoUpgradeMinorVersion') - ? extensionCustomScriptConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionCustomScriptConfig, 'enableAutomaticUpgrade') - ? extensionCustomScriptConfig.enableAutomaticUpgrade - : false + 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') @@ -912,18 +856,10 @@ module vm_azureDiskEncryptionExtension 'extension/main.bicep' = if (extensionAzu location: location publisher: 'Microsoft.Azure.Security' type: osType == 'Windows' ? 'AzureDiskEncryption' : 'AzureDiskEncryptionForLinux' - typeHandlerVersion: contains(extensionAzureDiskEncryptionConfig, 'typeHandlerVersion') - ? extensionAzureDiskEncryptionConfig.typeHandlerVersion - : (osType == 'Windows' ? '2.2' : '1.1') - autoUpgradeMinorVersion: contains(extensionAzureDiskEncryptionConfig, 'autoUpgradeMinorVersion') - ? extensionAzureDiskEncryptionConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionAzureDiskEncryptionConfig, 'enableAutomaticUpgrade') - ? extensionAzureDiskEncryptionConfig.enableAutomaticUpgrade - : false - forceUpdateTag: contains(extensionAzureDiskEncryptionConfig, 'forceUpdateTag') - ? extensionAzureDiskEncryptionConfig.forceUpdateTag - : '1.0' + 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 @@ -941,15 +877,9 @@ module vm_nvidiaGpuDriverWindowsExtension 'extension/main.bicep' = if (extension location: location publisher: 'Microsoft.HpcCompute' type: 'NvidiaGpuDriverWindows' - typeHandlerVersion: contains(extensionNvidiaGpuDriverWindows, 'typeHandlerVersion') - ? extensionNvidiaGpuDriverWindows.typeHandlerVersion - : '1.4' - autoUpgradeMinorVersion: contains(extensionNvidiaGpuDriverWindows, 'autoUpgradeMinorVersion') - ? extensionNvidiaGpuDriverWindows.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionNvidiaGpuDriverWindows, 'enableAutomaticUpgrade') - ? extensionNvidiaGpuDriverWindows.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionNvidiaGpuDriverWindows.?typeHandlerVersion ?? '1.4' + autoUpgradeMinorVersion: extensionNvidiaGpuDriverWindows.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionNvidiaGpuDriverWindows.?enableAutomaticUpgrade ?? false supressFailures: extensionNvidiaGpuDriverWindows.?supressFailures ?? false tags: extensionNvidiaGpuDriverWindows.?tags ?? tags } @@ -966,15 +896,9 @@ module vm_hostPoolRegistrationExtension 'extension/main.bicep' = if (extensionHo location: location publisher: 'Microsoft.PowerShell' type: 'DSC' - typeHandlerVersion: contains(extensionHostPoolRegistration, 'typeHandlerVersion') - ? extensionHostPoolRegistration.typeHandlerVersion - : '2.77' - autoUpgradeMinorVersion: contains(extensionHostPoolRegistration, 'autoUpgradeMinorVersion') - ? extensionHostPoolRegistration.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionHostPoolRegistration, 'enableAutomaticUpgrade') - ? extensionHostPoolRegistration.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionHostPoolRegistration.?typeHandlerVersion ?? '2.77' + autoUpgradeMinorVersion: extensionHostPoolRegistration.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionHostPoolRegistration.?enableAutomaticUpgrade ?? false settings: { modulesUrl: extensionHostPoolRegistration.modulesUrl configurationFunction: extensionHostPoolRegistration.configurationFunction @@ -1000,21 +924,11 @@ module vm_azureGuestConfigurationExtension 'extension/main.bicep' = if (extensio location: location publisher: 'Microsoft.GuestConfiguration' type: osType == 'Windows' ? 'ConfigurationforWindows' : 'ConfigurationForLinux' - typeHandlerVersion: contains(extensionGuestConfigurationExtension, 'typeHandlerVersion') - ? extensionGuestConfigurationExtension.typeHandlerVersion - : (osType == 'Windows' ? '1.0' : '1.0') - autoUpgradeMinorVersion: contains(extensionGuestConfigurationExtension, 'autoUpgradeMinorVersion') - ? extensionGuestConfigurationExtension.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionGuestConfigurationExtension, 'enableAutomaticUpgrade') - ? extensionGuestConfigurationExtension.enableAutomaticUpgrade - : true - forceUpdateTag: contains(extensionGuestConfigurationExtension, 'forceUpdateTag') - ? extensionGuestConfigurationExtension.forceUpdateTag - : '1.0' - settings: contains(extensionGuestConfigurationExtension, 'settings') - ? extensionGuestConfigurationExtension.settings - : {} + 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 diff --git a/avm/res/compute/virtual-machine/main.json b/avm/res/compute/virtual-machine/main.json index a92c91c855..de1432dd89 100644 --- a/avm/res/compute/virtual-machine/main.json +++ b/avm/res/compute/virtual-machine/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17479703443253656975" + "version": "0.30.3.12046", + "templateHash": "1443306495474212036" }, "name": "Virtual Machines", "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", @@ -975,7 +975,7 @@ }, "vm": { "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-03-01", + "apiVersion": "2024-07-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "identity": "[variables('identity')]", @@ -1047,10 +1047,10 @@ "count": "[length(parameters('nicConfigurations'))]", "input": { "properties": { - "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", + "deleteOption": "[coalesce(tryGet(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)))]" + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" } } ] @@ -1110,14 +1110,14 @@ "name": "[format('shutdown-computevm-{0}', parameters('name'))]", "location": "[parameters('location')]", "properties": { - "status": "[if(contains(parameters('autoShutdownConfig'), 'status'), parameters('autoShutdownConfig').status, 'Disabled')]", + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", "taskType": "ComputeVmShutdownTask", "dailyRecurrence": { - "time": "[if(contains(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), parameters('autoShutdownConfig').dailyRecurrenceTime, '19:00')]" + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" }, - "timeZoneId": "[if(contains(parameters('autoShutdownConfig'), 'timeZone'), parameters('autoShutdownConfig').timeZone, 'UTC')]", - "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationStatus'), createObject('status', if(contains(parameters('autoShutdownConfig'), 'notificationStatus'), parameters('autoShutdownConfig').notificationStatus, 'Disabled'), 'emailRecipient', if(contains(parameters('autoShutdownConfig'), 'notificationEmail'), parameters('autoShutdownConfig').notificationEmail, ''), 'notificationLocale', if(contains(parameters('autoShutdownConfig'), 'notificationLocale'), parameters('autoShutdownConfig').notificationLocale, 'en'), 'webhookUrl', if(contains(parameters('autoShutdownConfig'), 'notificationWebhookUrl'), parameters('autoShutdownConfig').notificationWebhookUrl, ''), 'timeInMinutes', if(contains(parameters('autoShutdownConfig'), 'notificationTimeInMinutes'), parameters('autoShutdownConfig').notificationTimeInMinutes, 30)), null())]" + "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" @@ -1206,17 +1206,25 @@ }, "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)))]", + "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": "[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()))]", + "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": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, "ipConfigurations": { "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" }, @@ -1243,8 +1251,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1517797599230349789" + "version": "0.30.3.12046", + "templateHash": "191716886366421622" } }, "definitions": { @@ -1533,7 +1541,7 @@ "name": "networkInterface_publicIPAddresses", "count": "[length(parameters('ipConfigurations'))]" }, - "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", + "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())]", @@ -1543,7 +1551,9 @@ }, "mode": "Incremental", "parameters": { - "name": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'name'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.name), createObject('value', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)))]", + "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')]" }, @@ -1562,16 +1572,30 @@ "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'))]", + "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": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", + "zones": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createArray(1, 2, 3))]" + }, "enableTelemetry": { "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" } @@ -1583,8 +1607,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.27.1.19265", - "templateHash": "10356333973104369631" + "version": "0.29.47.4906", + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -1596,6 +1620,13 @@ "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": { @@ -2009,6 +2040,13 @@ } }, "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')]", @@ -2019,15 +2057,15 @@ "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')]" + "Role Based Access Control Administrator": "[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.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "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": { @@ -2081,20 +2119,20 @@ "publicIpAddress_roleAssignments": { "copy": { "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), 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)]", + "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": "[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')]" + "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" @@ -2200,7 +2238,7 @@ { "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', if(contains(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'name'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.name, 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()))]" + "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()))]" } ] }, @@ -2236,8 +2274,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "1612343535299711142" + "version": "0.29.47.4906", + "templateHash": "9226998037927576702" }, "name": "Network Interface", "description": "This module deploys a Network Interface.", @@ -2369,6 +2407,13 @@ "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": { @@ -2571,6 +2616,13 @@ } }, "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')]", @@ -2579,15 +2631,15 @@ "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')]" + "Role Based Access Control Administrator": "[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))]", + "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": { @@ -2693,20 +2745,20 @@ "networkInterface_roleAssignments": { "copy": { "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), 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": "[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": "[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')]" + "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" @@ -2777,10 +2829,18 @@ "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()))]", + "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())]" }, @@ -2795,8 +2855,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -2979,9 +3039,15 @@ "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()))]", + "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]" }, @@ -3004,8 +3070,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3189,9 +3255,15 @@ "type": { "value": "IaaSAntimalware" }, - "typeHandlerVersion": "[if(contains(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAntiMalwareConfig').typeHandlerVersion), createObject('value', '1.3'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAntiMalwareConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAntiMalwareConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "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]" }, @@ -3209,8 +3281,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3415,8 +3487,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3598,12 +3670,18 @@ "value": "Microsoft.Azure.Monitoring.DependencyAgent" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDependencyAgentConfig').typeHandlerVersion), createObject('value', '9.10'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDependencyAgentConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDependencyAgentConfig').enableAutomaticUpgrade), createObject('value', true()))]", + "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": "[if(contains(parameters('extensionDependencyAgentConfig'), 'enableAMA'), parameters('extensionDependencyAgentConfig').enableAMA, true())]" + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" } }, "supressFailures": { @@ -3620,8 +3698,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3803,9 +3881,15 @@ "value": "Microsoft.Azure.NetworkWatcher" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').typeHandlerVersion), createObject('value', '1.4'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "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())]" }, @@ -3820,8 +3904,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4005,17 +4089,27 @@ "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()))]", + "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": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -4024,8 +4118,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4205,9 +4299,15 @@ }, "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()))]", + "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": [ @@ -4236,8 +4336,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4419,10 +4519,18 @@ "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'))]", + "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())]" }, @@ -4440,8 +4548,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4625,9 +4733,15 @@ "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()))]", + "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())]" }, @@ -4642,8 +4756,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4827,9 +4941,15 @@ "type": { "value": "DSC" }, - "typeHandlerVersion": "[if(contains(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), createObject('value', parameters('extensionHostPoolRegistration').typeHandlerVersion), createObject('value', '2.77'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionHostPoolRegistration').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionHostPoolRegistration').enableAutomaticUpgrade), createObject('value', false()))]", + "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]", @@ -4853,8 +4973,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -5034,11 +5154,21 @@ "value": "Microsoft.GuestConfiguration" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), createObject('value', parameters('extensionGuestConfigurationExtension').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.0'), createObject('value', '1.0')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionGuestConfigurationExtension').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionGuestConfigurationExtension').enableAutomaticUpgrade), createObject('value', true()))]", - "forceUpdateTag": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), createObject('value', parameters('extensionGuestConfigurationExtension').forceUpdateTag), createObject('value', '1.0'))]", - "settings": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject('value', parameters('extensionGuestConfigurationExtension').settings), createObject('value', createObject()))]", + "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())]" }, @@ -5056,8 +5186,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -5255,8 +5385,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4676289166883418684" + "version": "0.30.3.12046", + "templateHash": "18427642917647797213" }, "name": "Recovery Service Vaults Protection Container Protected Item", "description": "This module deploys a Recovery Services Vault Protection Container Protected Item.", @@ -5390,14 +5520,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('vm', '2024-03-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(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-03-01', 'full').location]" + "value": "[reference('vm', '2024-07-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/compute/virtual-machine/modules/nic-configuration.bicep b/avm/res/compute/virtual-machine/modules/nic-configuration.bicep index 19f46b427f..9c6bad7362 100644 --- a/avm/res/compute/virtual-machine/modules/nic-configuration.bicep +++ b/avm/res/compute/virtual-machine/modules/nic-configuration.bicep @@ -27,51 +27,38 @@ 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.4.1' = [ - for (ipConfiguration, index) in ipConfigurations: if (contains(ipConfiguration, 'pipConfiguration')) { +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: contains(ipConfiguration.pipConfiguration, 'name') - ? ipConfiguration.pipConfiguration.name - : '${virtualMachineName}${ipConfiguration.pipConfiguration.publicIpNameSuffix}' + 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: contains(ipConfiguration.pipConfiguration, 'publicIPAddressVersion') - ? ipConfiguration.pipConfiguration.publicIPAddressVersion - : 'IPv4' - publicIPAllocationMethod: contains(ipConfiguration.pipConfiguration, 'publicIPAllocationMethod') - ? ipConfiguration.pipConfiguration.publicIPAllocationMethod - : 'Static' - publicIpPrefixResourceId: contains(ipConfiguration.pipConfiguration, 'publicIPPrefixResourceId') - ? ipConfiguration.pipConfiguration.publicIPPrefixResourceId - : '' - roleAssignments: contains(ipConfiguration.pipConfiguration, 'roleAssignments') - ? ipConfiguration.pipConfiguration.roleAssignments - : [] - skuName: contains(ipConfiguration.pipConfiguration, 'skuName') - ? ipConfiguration.pipConfiguration.skuName - : 'Standard' - skuTier: contains(ipConfiguration.pipConfiguration, 'skuTier') - ? ipConfiguration.pipConfiguration.skuTier - : 'Regional' + 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: contains(ipConfiguration.pipConfiguration, 'zones') - ? ipConfiguration.pipConfiguration.zones - : [ - 1 - 2 - 3 - ] + zones: ipConfiguration.pipConfiguration.?zones ?? [ + 1 + 2 + 3 + ] enableTelemetry: ipConfiguration.?enableTelemetry ?? enableTelemetry } } ] -module networkInterface 'br/public:avm/res/network/network-interface:0.2.4' = { +module networkInterface 'br/public:avm/res/network/network-interface:0.4.0' = { name: '${deployment().name}-NetworkInterface' params: { name: networkInterfaceName @@ -86,33 +73,21 @@ module networkInterface 'br/public:avm/res/network/network-interface:0.2.4' = { ? (!empty(ipConfiguration.privateIPAddress) ? ipConfiguration.privateIPAddress : null) : null publicIPAddressResourceId: contains(ipConfiguration, 'pipConfiguration') - ? resourceId( - 'Microsoft.Network/publicIPAddresses', - contains(ipConfiguration.pipConfiguration, 'name') - ? ipConfiguration.pipConfiguration.name - : '${virtualMachineName}${ipConfiguration.pipConfiguration.publicIpNameSuffix}' - ) + ? !contains(ipConfiguration.pipConfiguration, 'publicIPAddressResourceId') + ? resourceId( + 'Microsoft.Network/publicIPAddresses', + ipConfiguration.pipConfiguration.?name ?? '${virtualMachineName}${ipConfiguration.pipConfiguration.?publicIpNameSuffix}' + ) + : ipConfiguration.pipConfiguration.publicIPAddressResourceId : null subnetResourceId: 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 + 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 diff --git a/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep index 32e5a29dec..fcfd8d428d 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep @@ -1,3 +1,4 @@ +// 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.' @@ -11,8 +12,9 @@ metadata description = 'This instance deploys the module with registering to an @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -20,10 +22,6 @@ param serviceShort string = 'cvmlinatmg' @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 (configurationProfileAssignments) -// Right now (2024/04) the following locations are supported: centralus, eastus, eastus2, southcentralus, westus, westus2, westcentralus, northeurope, westeurope, canadacentral, japaneast, uksouth, australiasoutheast, australiaeast, southeastasia, westus3 -param enforcedLocation string = 'westeurope' - // ============ // // Dependencies // // ============ // @@ -32,7 +30,7 @@ param enforcedLocation string = 'westeurope' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { @@ -58,7 +56,7 @@ module nestedDependencies 'dependencies.bicep' = { @batchSize(1) module testDeployment '../../../main.bicep' = [ - for iteration in ['init', 'idem']: { + for iteration in ['init', 'idem']: if (false) { scope: resourceGroup name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { @@ -98,7 +96,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' configurationProfile: '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' disablePasswordAuthentication: true publicKeys: [ diff --git a/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep index f0d5ccaa71..16959ce774 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -28,14 +29,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' @@ -56,9 +57,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -90,7 +91,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' disablePasswordAuthentication: true publicKeys: [ { diff --git a/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep index b0b2b53a5a..f19060fba7 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep @@ -34,7 +34,7 @@ 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. Required for Customer-Managed-Keys.') +@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.') diff --git a/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep index 6b1d1a4e1e..cd05048ddb 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -32,14 +33,14 @@ param backupManagementServiceEnterpriseApplicationObjectId string = '' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' @@ -60,13 +61,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + 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: resourceLocation + location: enforcedLocation } } @@ -76,11 +77,11 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' params: { name: '${namePrefix}${serviceShort}' computerName: '${namePrefix}linvm1' - location: resourceLocation + location: enforcedLocation adminUsername: 'localAdministrator' imageReference: { publisher: 'Canonical' @@ -199,7 +200,7 @@ module testDeployment '../../../main.bicep' = { } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 1 backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName backupVaultName: nestedDependencies.outputs.recoveryServicesVaultName diff --git a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep index 795ab9dfa7..15da56837a 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep @@ -31,7 +31,7 @@ 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. Required for Customer-Managed-Keys.') +@description('Required. The object ID of the Backup Management Service Enterprise Application.') param backupManagementServiceApplicationObjectId string @description('Required. The name of the data collection rule.') diff --git a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep index fd619b1589..45ba5ad582 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -36,14 +37,14 @@ param backupManagementServiceEnterpriseApplicationObjectId string = '' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' maintenanceConfigurationName: 'dep-${namePrefix}-mc-${serviceShort}' applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' @@ -64,13 +65,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + 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: resourceLocation + location: enforcedLocation } } @@ -82,9 +83,9 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' computerName: '${namePrefix}winvm1' adminUsername: 'VMAdmin' @@ -176,7 +177,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password zone: 2 backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep index 7232384320..db778bf326 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -32,14 +33,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' } } @@ -51,9 +52,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -82,7 +83,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password } } diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep index 0db2535978..e719018cf5 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the a guest config @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -32,14 +33,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' } } @@ -51,12 +52,12 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { managedIdentities: { systemAssigned: true } - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -72,6 +73,10 @@ module testDeployment '../../../main.bicep' = [ { name: 'ipconfig01' subnetResourceId: nestedDependencies.outputs.subnetResourceId + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } } ] nicSuffix: '-nic-01' @@ -85,7 +90,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password extensionGuestConfigurationExtension: { enabled: true diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep index e13b61d4e3..06cb5b6633 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module and registers it in a h @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -24,10 +25,6 @@ param password string = newGuid() @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/04) the following locations are supported: centralindia,uksouth,ukwest,japaneast,australiaeast,canadaeast,canadacentral,northeurope,westeurope,eastus,eastus2,westus,westus2,westus3,northcentralus,southcentralus,westcentralus,centralus -param enforcedLocation string = 'westeurope' - // ============ // // Dependencies // // ============ // @@ -36,7 +33,7 @@ param enforcedLocation string = 'westeurope' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { @@ -58,7 +55,7 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { location: enforcedLocation name: '${namePrefix}${serviceShort}' @@ -92,7 +89,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password extensionAadJoinConfig: { enabled: true diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep index a492ad2a5a..bccba3d29d 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep @@ -10,6 +10,9 @@ 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 @@ -28,7 +31,7 @@ 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. Required for Customer-Managed-Keys.') +@description('Required. The object ID of the Backup Management Service Enterprise Application.') param backupManagementServiceApplicationObjectId string @description('Required. The name of the data collection rule.') @@ -108,6 +111,17 @@ resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { } } +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 @@ -404,6 +418,9 @@ 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 diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep index ac79b215ce..96c3d990e2 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -36,17 +37,18 @@ param backupManagementServiceEnterpriseApplicationObjectId string = '' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + 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}' @@ -63,13 +65,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + 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: resourceLocation + location: enforcedLocation } } @@ -81,9 +83,9 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' computerName: '${namePrefix}winvm1' adminUsername: 'VMAdmin' @@ -110,12 +112,7 @@ module testDeployment '../../../main.bicep' = [ ] name: 'ipconfig01' pipConfiguration: { - publicIpNameSuffix: '-pip-01' - zones: [ - 1 - 2 - 3 - ] + publicIPAddressResourceId: nestedDependencies.outputs.publicIPAddressResourceId roleAssignments: [ { name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' @@ -205,7 +202,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password zone: 2 backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep index 035c2446ed..0b8df1ac01 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep @@ -11,6 +11,10 @@ metadata description = 'This instance deploys the module for a VM with dedicated @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' @@ -21,9 +25,6 @@ param password string = newGuid() @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -#disable-next-line no-hardcoded-location // Due to quotas and capacity challenges, this region must be used in the AVM testing subscription -var enforcedLocation = 'eastus' - // ============ // // Dependencies // // ============ // diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep index e3edaf2352..8c9e1a248c 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with disk enryption set @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -35,14 +36,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + 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)}' @@ -57,9 +58,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'VMAdministrator' imageReference: { @@ -90,7 +91,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password dataDisks: [ { diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep index 55485d9ede..aa14a3502f 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// 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' @@ -32,14 +33,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' vmssName: 'dep-${namePrefix}-vmss-${serviceShort}' pipName: 'dep-${namePrefix}-pip-${serviceShort}' @@ -54,9 +55,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -85,7 +86,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password virtualMachineScaleSetResourceId: nestedDependencies.outputs.vmssResourceId } diff --git a/avm/res/compute/virtual-machine/version.json b/avm/res/compute/virtual-machine/version.json index 09c3664cec..9a9a06e897 100644 --- a/avm/res/compute/virtual-machine/version.json +++ b/avm/res/compute/virtual-machine/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.7", + "version": "0.8", "pathFilters": [ "./main.json" ] From 13e77ed4f80d7481ed630f2eb1a972b161350069 Mon Sep 17 00:00:00 2001 From: Eric Scheffler <70648471+ericscheffler@users.noreply.github.com> Date: Wed, 9 Oct 2024 13:34:54 -0400 Subject: [PATCH 47/93] feat: VPN Server Configuration resource (#3400) ## Description This PR introduces a new resource to create VPN Server Configurations within an Azure Virtual WAN, usable by P2S VPN Gateways within a VWAN Virtual Hub. This resource requires a Virtual WAN, but does not require a Virtual Hub to exist before creating the VPN Server Configuration. Closes Issue [#1333](https://github.com/Azure/Azure-Verified-Modules/issues/1333) ## Pipeline Reference [![avm.res.network.vpn-server-configuration](https://github.com/ericscheffler/bicep-registry-modules/actions/workflows/avm.res.network.vpn-server-configuration.yml/badge.svg?branch=Issue1333-vpn-server-configuration)](https://github.com/ericscheffler/bicep-registry-modules/actions/workflows/avm.res.network.vpn-server-configuration.yml) ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: erschef_microsoft --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + ...m.res.network.vpn-server-configuration.yml | 88 ++ .../vpn-server-configuration/README.md | 1022 +++++++++++++++++ .../vpn-server-configuration/main.bicep | 224 ++++ .../vpn-server-configuration/main.json | 404 +++++++ .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 82 ++ .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 163 +++ .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 83 ++ .../vpn-server-configuration/version.json | 7 + 13 files changed, 2114 insertions(+) create mode 100644 .github/workflows/avm.res.network.vpn-server-configuration.yml create mode 100644 avm/res/network/vpn-server-configuration/README.md create mode 100644 avm/res/network/vpn-server-configuration/main.bicep create mode 100644 avm/res/network/vpn-server-configuration/main.json create mode 100644 avm/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep create mode 100644 avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/network/vpn-server-configuration/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 400d91ac7a..fa10327b3b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -133,6 +133,7 @@ /avm/res/network/virtual-network-gateway/ @Azure/avm-res-network-virtualnetworkgateway-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/network/virtual-wan/ @Azure/avm-res-network-virtualwan-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/network/vpn-gateway/ @Azure/avm-res-network-vpngateway-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/network/vpn-server-configuration/ @Azure/avm-res-network-vpnserverconfiguration-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/network/vpn-site/ @Azure/avm-res-network-vpnsite-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/operational-insights/workspace/ @Azure/avm-res-operationalinsights-workspace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/operations-management/solution/ @Azure/avm-res-operationsmanagement-solution-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index f5f78969d2..b0573101fb 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -168,6 +168,7 @@ body: - "avm/res/network/virtual-network-gateway" - "avm/res/network/virtual-wan" - "avm/res/network/vpn-gateway" + - "avm/res/network/vpn-server-configuration" - "avm/res/network/vpn-site" - "avm/res/operational-insights/workspace" - "avm/res/operations-management/solution" diff --git a/.github/workflows/avm.res.network.vpn-server-configuration.yml b/.github/workflows/avm.res.network.vpn-server-configuration.yml new file mode 100644 index 0000000000..785cee942d --- /dev/null +++ b/.github/workflows/avm.res.network.vpn-server-configuration.yml @@ -0,0 +1,88 @@ +name: "avm.res.network.vpn-server-configuration" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.network.vpn-server-configuration.yml" + - "avm/res/network/vpn-server-configuration/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/network/vpn-server-configuration" + workflowPath: ".github/workflows/avm.res.network.vpn-server-configuration.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/network/vpn-server-configuration/README.md b/avm/res/network/vpn-server-configuration/README.md new file mode 100644 index 0000000000..a21f461ce1 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/README.md @@ -0,0 +1,1022 @@ +# 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) +- [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: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + location: '' + 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": "https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111" + }, + "location": { + "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 = 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' +param location = '' +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: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + 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": "https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111" + }, + "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 = 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' +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: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + location: '' + 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": "https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111" + }, + "location": { + "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 = 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' +param location = '' +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. | + +## 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/res/network/vpn-server-configuration/main.bicep b/avm/res/network/vpn-server-configuration/main.bicep new file mode 100644 index 0000000000..b4a86adba5 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/main.bicep @@ -0,0 +1,224 @@ +metadata name = 'VPN Server Configuration' +metadata description = 'This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway.' +metadata owner = 'Azure/module-maintainers' + +@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? + +@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 // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +@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/res/network/vpn-server-configuration/main.json b/avm/res/network/vpn-server-configuration/main.json new file mode 100644 index 0000000000..c7b7b25c43 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/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.30.23.60470", + "templateHash": "17638255215829732671" + }, + "name": "VPN Server Configuration", + "description": "This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway.", + "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 + }, + "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 + } + } + }, + "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", + "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/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..3e28ec067b --- /dev/null +++ b/avm/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/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..0a4ae3b7e7 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,82 @@ +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: { + location: resourceLocation + name: '${namePrefix}${serviceShort}VPNConfig' + 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' + 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/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..3e28ec067b --- /dev/null +++ b/avm/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/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..f40181a92a --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep @@ -0,0 +1,163 @@ +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: 'https://login.microsoftonline.com/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/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..bb151ad9d8 --- /dev/null +++ b/avm/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/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..02e29e4f93 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,83 @@ +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: { + location: resourceLocation + name: '${namePrefix}${serviceShort}VPNConfig' + 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' + 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/res/network/vpn-server-configuration/version.json b/avm/res/network/vpn-server-configuration/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/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" + ] +} From 2f08e570426bbeeca08ce1acf34089b9649c64c6 Mon Sep 17 00:00:00 2001 From: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> Date: Wed, 9 Oct 2024 18:39:51 +0100 Subject: [PATCH 48/93] fix: Forwarding Ruleset property change from string to int (#3494) ## Description Closes #3347 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.dns-forwarding-ruleset](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml/badge.svg?branch=dnsfrs-int-fix&event=workflow_dispatch)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml)| ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [x] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/network/dns-forwarding-ruleset/README.md | 10 +++++----- .../forwarding-rule/main.json | 4 ++-- avm/res/network/dns-forwarding-ruleset/main.bicep | 2 +- avm/res/network/dns-forwarding-ruleset/main.json | 14 +++++++------- .../tests/e2e/max/main.test.bicep | 2 +- .../network/dns-forwarding-ruleset/version.json | 2 +- .../virtual-network-link/main.json | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/avm/res/network/dns-forwarding-ruleset/README.md b/avm/res/network/dns-forwarding-ruleset/README.md index d04be125ef..8e1cb79b7d 100644 --- a/avm/res/network/dns-forwarding-ruleset/README.md +++ b/avm/res/network/dns-forwarding-ruleset/README.md @@ -134,7 +134,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset: Date: Thu, 10 Oct 2024 02:14:20 +0800 Subject: [PATCH 49/93] feat: Updated module name from `avm/ptn/azd/container-apps` to `avm/ptn/azd/container-apps-stack` (#3452) ## Description `avm/ptn/azd/container-apps` => `avm/ptn/azd/container-apps-stack` ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.container-apps-stack](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-apps-stack.yml/badge.svg?branch=container-apps-stack-update)](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-apps-stack.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --- .github/CODEOWNERS | 2 +- .github/ISSUE_TEMPLATE/avm_module_issue.yml | 2 +- ...l => avm.ptn.azd.container-apps-stack.yml} | 10 ++++---- .../README.md | 24 ++++++++++--------- .../main.bicep | 8 ++++--- .../main.json | 10 ++++---- .../e2e/zone-redundant/dependencies.bicep | 0 .../tests/e2e/zone-redundant/main.test.bicep | 4 ++-- .../version.json | 0 9 files changed, 32 insertions(+), 28 deletions(-) rename .github/workflows/{avm.ptn.azd.container-apps.yml => avm.ptn.azd.container-apps-stack.yml} (90%) rename avm/ptn/azd/{container-apps => container-apps-stack}/README.md (94%) rename avm/ptn/azd/{container-apps => container-apps-stack}/main.bicep (91%) rename avm/ptn/azd/{container-apps => container-apps-stack}/main.json (99%) rename avm/ptn/azd/{container-apps => container-apps-stack}/tests/e2e/zone-redundant/dependencies.bicep (100%) rename avm/ptn/azd/{container-apps => container-apps-stack}/tests/e2e/zone-redundant/main.test.bicep (97%) rename avm/ptn/azd/{container-apps => container-apps-stack}/version.json (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fa10327b3b..a060083148 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,7 +13,7 @@ #/avm/ptn/avd-lza/networking/ @Azure/avm-ptn-avd-lza-networking-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/session-hosts/ @Azure/avm-ptn-avd-lza-sessionhosts-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep -/avm/ptn/azd/container-apps/ @Azure/avm-ptn-azd-containerapps-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/dev-ops/cicd-agents-and-runners/ @Azure/avm-ptn-devops-cicdagentsandrunners-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index b0573101fb..610c26742c 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -48,7 +48,7 @@ body: # - "avm/ptn/avd-lza/networking" # - "avm/ptn/avd-lza/session-hosts" - "avm/ptn/azd/apim-api" - - "avm/ptn/azd/container-apps" + - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - "avm/ptn/deployment-script/import-image-to-acr" - "avm/ptn/dev-ops/cicd-agents-and-runners" diff --git a/.github/workflows/avm.ptn.azd.container-apps.yml b/.github/workflows/avm.ptn.azd.container-apps-stack.yml similarity index 90% rename from .github/workflows/avm.ptn.azd.container-apps.yml rename to .github/workflows/avm.ptn.azd.container-apps-stack.yml index 0759231151..7a057fef70 100644 --- a/.github/workflows/avm.ptn.azd.container-apps.yml +++ b/.github/workflows/avm.ptn.azd.container-apps-stack.yml @@ -1,4 +1,4 @@ -name: "avm.ptn.azd.container-apps" +name: "avm.ptn.azd.container-apps-stack" on: workflow_dispatch: @@ -28,15 +28,15 @@ on: paths: - ".github/actions/templates/avm-**" - ".github/workflows/avm.template.module.yml" - - ".github/workflows/avm.ptn.azd.container-apps.yml" - - "avm/ptn/azd/container-apps/**" + - ".github/workflows/avm.ptn.azd.container-apps-stack.yml" + - "avm/ptn/azd/container-apps-stack/**" - "avm/utilities/pipelines/**" - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: - modulePath: "avm/ptn/azd/container-apps" - workflowPath: ".github/workflows/avm.ptn.azd.container-apps.yml" + modulePath: "avm/ptn/azd/container-apps-stack" + workflowPath: ".github/workflows/avm.ptn.azd.container-apps-stack.yml" concurrency: group: ${{ github.workflow }} diff --git a/avm/ptn/azd/container-apps/README.md b/avm/ptn/azd/container-apps-stack/README.md similarity index 94% rename from avm/ptn/azd/container-apps/README.md rename to avm/ptn/azd/container-apps-stack/README.md index 742a2f8be8..1702795bd4 100644 --- a/avm/ptn/azd/container-apps/README.md +++ b/avm/ptn/azd/container-apps-stack/README.md @@ -1,7 +1,9 @@ -# avm/ptn/azd/container-apps `[Azd/ContainerApps]` +# avm/ptn/azd/container-apps-stack `[Azd/ContainerAppsStack]` Creates an Azure Container Registry and an Azure Container Apps environment. +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case + ## Navigation - [Resource Types](#Resource-Types) @@ -35,7 +37,7 @@ The following section provides usage examples for the module, which were used to >**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/azd/container-apps:`. +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/azd/container-apps-stack:`. - [With zoneRedundant enabled](#example-1-with-zoneredundant-enabled) @@ -49,12 +51,12 @@ This instance deploys the module with zoneRedundant enabled.

    via Bicep module ```bicep -module containerApps 'br/public:avm/ptn/azd/container-apps:' = { - name: 'containerAppsDeployment' +module containerAppsStack 'br/public:avm/ptn/azd/container-apps-stack:' = { + name: 'containerAppsStackDeployment' params: { // Required parameters - containerAppsEnvironmentName: 'acazrcae001' - containerRegistryName: 'acazrcr001' + containerAppsEnvironmentName: 'acaszrcae001' + containerRegistryName: 'acaszrcr001' logAnalyticsWorkspaceResourceId: '' // Non-required parameters acrSku: 'Standard' @@ -92,10 +94,10 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = { "parameters": { // Required parameters "containerAppsEnvironmentName": { - "value": "acazrcae001" + "value": "acaszrcae001" }, "containerRegistryName": { - "value": "acazrcr001" + "value": "acaszrcr001" }, "logAnalyticsWorkspaceResourceId": { "value": "" @@ -150,11 +152,11 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = { via Bicep parameters file ```bicep-params -using 'br/public:avm/ptn/azd/container-apps:' +using 'br/public:avm/ptn/azd/container-apps-stack:' // Required parameters -param containerAppsEnvironmentName = 'acazrcae001' -param containerRegistryName = 'acazrcr001' +param containerAppsEnvironmentName = 'acaszrcae001' +param containerRegistryName = 'acaszrcr001' param logAnalyticsWorkspaceResourceId = '' // Non-required parameters param acrSku = 'Standard' diff --git a/avm/ptn/azd/container-apps/main.bicep b/avm/ptn/azd/container-apps-stack/main.bicep similarity index 91% rename from avm/ptn/azd/container-apps/main.bicep rename to avm/ptn/azd/container-apps-stack/main.bicep index 9a99522cd4..1319e17f2d 100644 --- a/avm/ptn/azd/container-apps/main.bicep +++ b/avm/ptn/azd/container-apps-stack/main.bicep @@ -1,5 +1,7 @@ -metadata name = 'avm/ptn/azd/container-apps' -metadata description = 'Creates an Azure Container Registry and an Azure Container Apps environment.' +metadata name = 'avm/ptn/azd/container-apps-stack' +metadata description = '''Creates an Azure Container Registry and an Azure Container Apps environment. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case''' metadata owner = 'Azure/module-maintainers' @description('Optional. Location for all Resources.') @@ -68,7 +70,7 @@ param infrastructureResourceGroupName string = take('ME_${containerAppsEnvironme #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { - name: '46d3xbcp.ptn.azd-containerapps.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + name: '46d3xbcp.ptn.azd-containerappsstack.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' properties: { mode: 'Incremental' template: { diff --git a/avm/ptn/azd/container-apps/main.json b/avm/ptn/azd/container-apps-stack/main.json similarity index 99% rename from avm/ptn/azd/container-apps/main.json rename to avm/ptn/azd/container-apps-stack/main.json index b781ce346e..f58de2af0b 100644 --- a/avm/ptn/azd/container-apps/main.json +++ b/avm/ptn/azd/container-apps-stack/main.json @@ -5,11 +5,11 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "3154922260961626340" + "version": "0.29.47.4906", + "templateHash": "332940780345983600" }, - "name": "avm/ptn/azd/container-apps", - "description": "Creates an Azure Container Registry and an Azure Container Apps environment.", + "name": "avm/ptn/azd/container-apps-stack", + "description": "Creates an Azure Container Registry and an Azure Container Apps environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", "owner": "Azure/module-maintainers" }, "parameters": { @@ -154,7 +154,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.ptn.azd-containerapps.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.ptn.azd-containerappsstack.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { diff --git a/avm/ptn/azd/container-apps/tests/e2e/zone-redundant/dependencies.bicep b/avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/dependencies.bicep similarity index 100% rename from avm/ptn/azd/container-apps/tests/e2e/zone-redundant/dependencies.bicep rename to avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/dependencies.bicep diff --git a/avm/ptn/azd/container-apps/tests/e2e/zone-redundant/main.test.bicep b/avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/main.test.bicep similarity index 97% rename from avm/ptn/azd/container-apps/tests/e2e/zone-redundant/main.test.bicep rename to avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/main.test.bicep index 19ec8ef14a..06ec762ffc 100644 --- a/avm/ptn/azd/container-apps/tests/e2e/zone-redundant/main.test.bicep +++ b/avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/main.test.bicep @@ -8,13 +8,13 @@ metadata description = 'This instance deploys the module with zoneRedundant enab // ========== // @description('Optional. The name of the resource group to deploy for testing purposes.') @maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-container-apps-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-container-apps-stack-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'acazr' +param serviceShort string = 'acaszr' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' diff --git a/avm/ptn/azd/container-apps/version.json b/avm/ptn/azd/container-apps-stack/version.json similarity index 100% rename from avm/ptn/azd/container-apps/version.json rename to avm/ptn/azd/container-apps-stack/version.json From 83767238fba881f06548b48bff8e50a940e3e256 Mon Sep 17 00:00:00 2001 From: Anders Eide Date: Wed, 9 Oct 2024 20:48:17 +0200 Subject: [PATCH 50/93] fix: Front door web application firewall policy api version and types - `avm/res/network/front-door-web-application-firewall-policy` (#2989) ## Description Changed api version number on the frontDoorWAFPolicy resource Added types for managedRules and customRules to make the module more user friendly. Fixes #2988 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.front-door-web-application-firewall-policy](https://github.com/anderseide/avm-bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml/badge.svg?branch=front-door-web-application-firewall-policy&event=workflow_dispatch)](https://github.com/anderseide/avm-bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../README.md | 183 +++++++++++++++++- .../main.bicep | 59 +++++- .../main.json | 154 ++++++++++++++- 3 files changed, 386 insertions(+), 10 deletions(-) diff --git a/avm/res/network/front-door-web-application-firewall-policy/README.md b/avm/res/network/front-door-web-application-firewall-policy/README.md index 97df30f6ba..830c52b31e 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/README.md +++ b/avm/res/network/front-door-web-application-firewall-policy/README.md @@ -16,7 +16,7 @@ This module deploys a Front Door Web Application Firewall (WAF) Policy. | :-- | :-- | | `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` | [2022-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-05-01/FrontDoorWebApplicationFirewallPolicies) | +| `Microsoft.Network/FrontDoorWebApplicationFirewallPolicies` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/FrontDoorWebApplicationFirewallPolicies) | ## Usage examples @@ -783,6 +783,116 @@ The custom rules inside the policy. } ``` +**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. @@ -862,6 +972,77 @@ Describes the managedRules structure. } ``` +**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. diff --git a/avm/res/network/front-door-web-application-firewall-policy/main.bicep b/avm/res/network/front-door-web-application-firewall-policy/main.bicep index 377833654b..9d6421a9b8 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/main.bicep +++ b/avm/res/network/front-door-web-application-firewall-policy/main.bicep @@ -24,7 +24,7 @@ param tags object? param enableTelemetry bool = true @description('Optional. Describes the managedRules structure.') -param managedRules object = { +param managedRules managedRulesType = { managedRuleSets: [ { ruleSetType: 'Microsoft_DefaultRuleSet' @@ -43,7 +43,7 @@ param managedRules object = { } @description('Optional. The custom rules inside the policy.') -param customRules object = { +param customRules customRulesType = { rules: [ { name: 'ApplyGeoFilter' @@ -119,7 +119,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource frontDoorWAFPolicy 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2022-05-01' = { +resource frontDoorWAFPolicy 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2024-02-01' = { name: name location: location sku: { @@ -213,3 +213,56 @@ type roleAssignmentType = { @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/res/network/front-door-web-application-firewall-policy/main.json b/avm/res/network/front-door-web-application-firewall-policy/main.json index de8d1b031c..8048f5de23 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/main.json +++ b/avm/res/network/front-door-web-application-firewall-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8148563999971279398" + "version": "0.30.23.60470", + "templateHash": "13657670923843039959" }, "name": "Front Door Web Application Firewall (WAF) Policies", "description": "This module deploys a Front Door Web Application Firewall (WAF) Policy.", @@ -110,6 +110,148 @@ } }, "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": { @@ -154,7 +296,7 @@ } }, "managedRules": { - "type": "object", + "$ref": "#/definitions/managedRulesType", "defaultValue": { "managedRuleSets": [ { @@ -177,7 +319,7 @@ } }, "customRules": { - "type": "object", + "$ref": "#/definitions/customRulesType", "defaultValue": { "rules": [ { @@ -265,7 +407,7 @@ }, "frontDoorWAFPolicy": { "type": "Microsoft.Network/FrontDoorWebApplicationFirewallPolicies", - "apiVersion": "2022-05-01", + "apiVersion": "2024-02-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "sku": { @@ -342,7 +484,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('frontDoorWAFPolicy', '2022-05-01', 'full').location]" + "value": "[reference('frontDoorWAFPolicy', '2024-02-01', 'full').location]" } } } \ No newline at end of file From 7b01fc50999f2a1cad007a9643c7c7e40f2909aa Mon Sep 17 00:00:00 2001 From: hundredacres Date: Wed, 9 Oct 2024 12:38:21 -0700 Subject: [PATCH 51/93] fix: Add param file examples to README and fixed safe access operator usage (#3447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Updating README with param file examples. Fixed safe access operator alerts. Fixes #3423 Closes #3423 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.db-for-my-sql.flexible-server](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml/badge.svg?branch=fix%2Fissues%2F3423)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [X] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [X] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [X] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth Co-authored-by: Alexander Sehr --- .../flexible-server/administrator/main.json | 4 +-- .../flexible-server/database/main.json | 4 +-- .../flexible-server/firewall-rule/main.json | 4 +-- .../db-for-my-sql/flexible-server/main.bicep | 6 ++-- .../db-for-my-sql/flexible-server/main.json | 28 +++++++++++-------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/avm/res/db-for-my-sql/flexible-server/administrator/main.json b/avm/res/db-for-my-sql/flexible-server/administrator/main.json index a08e31dfad..e01bbabdc8 100644 --- a/avm/res/db-for-my-sql/flexible-server/administrator/main.json +++ b/avm/res/db-for-my-sql/flexible-server/administrator/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "166868353165081250" + "version": "0.30.3.12046", + "templateHash": "17380647846007156110" }, "name": "DBforMySQL Flexible Server Administrators", "description": "This module deploys a DBforMySQL Flexible Server Administrator.", diff --git a/avm/res/db-for-my-sql/flexible-server/database/main.json b/avm/res/db-for-my-sql/flexible-server/database/main.json index 3ecb2da053..de30c026df 100644 --- a/avm/res/db-for-my-sql/flexible-server/database/main.json +++ b/avm/res/db-for-my-sql/flexible-server/database/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11351866916144767840" + "version": "0.30.3.12046", + "templateHash": "15491679806037869848" }, "name": "DBforMySQL Flexible Server Databases", "description": "This module deploys a DBforMySQL Flexible Server Database.", diff --git a/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json b/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json index 06fc052a20..a79df47833 100644 --- a/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json +++ b/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17406464450077393680" + "version": "0.30.3.12046", + "templateHash": "10498063087675421166" }, "name": "DBforMySQL Flexible Server Firewall Rules", "description": "This module deploys a DBforMySQL Flexible Server Firewall Rule.", diff --git a/avm/res/db-for-my-sql/flexible-server/main.bicep b/avm/res/db-for-my-sql/flexible-server/main.bicep index 0cdfde042a..cea96cf71d 100644 --- a/avm/res/db-for-my-sql/flexible-server/main.bicep +++ b/avm/res/db-for-my-sql/flexible-server/main.bicep @@ -371,8 +371,8 @@ module flexibleServer_databases 'database/main.bicep' = [ params: { name: database.name flexibleServerName: flexibleServer.name - collation: contains(database, 'collation') ? database.collation : '' - charset: contains(database, 'charset') ? database.charset : '' + collation: database.?collation ?? '' + charset: database.?charset ?? '' } } ] @@ -397,7 +397,7 @@ module flexibleServer_administrators 'administrator/main.bicep' = [ login: administrator.login sid: administrator.sid identityResourceId: administrator.identityResourceId - tenantId: contains(administrator, 'tenantId') ? administrator.tenantId : tenant().tenantId + tenantId: administrator.?tenantId ?? tenant().tenantId } } ] diff --git a/avm/res/db-for-my-sql/flexible-server/main.json b/avm/res/db-for-my-sql/flexible-server/main.json index ba56f19217..4073cc3021 100644 --- a/avm/res/db-for-my-sql/flexible-server/main.json +++ b/avm/res/db-for-my-sql/flexible-server/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4552759122514680729" + "version": "0.30.3.12046", + "templateHash": "17022862459992031093" }, "name": "DBforMySQL Flexible Servers", "description": "This module deploys a DBforMySQL Flexible Server.", @@ -817,8 +817,12 @@ "flexibleServerName": { "value": "[parameters('name')]" }, - "collation": "[if(contains(parameters('databases')[copyIndex()], 'collation'), createObject('value', parameters('databases')[copyIndex()].collation), createObject('value', ''))]", - "charset": "[if(contains(parameters('databases')[copyIndex()], 'charset'), createObject('value', parameters('databases')[copyIndex()].charset), createObject('value', ''))]" + "collation": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'collation'), '')]" + }, + "charset": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'charset'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -826,8 +830,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11351866916144767840" + "version": "0.30.3.12046", + "templateHash": "15491679806037869848" }, "name": "DBforMySQL Flexible Server Databases", "description": "This module deploys a DBforMySQL Flexible Server Database.", @@ -934,8 +938,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17406464450077393680" + "version": "0.30.3.12046", + "templateHash": "10498063087675421166" }, "name": "DBforMySQL Flexible Server Firewall Rules", "description": "This module deploys a DBforMySQL Flexible Server Firewall Rule.", @@ -1033,7 +1037,9 @@ "identityResourceId": { "value": "[parameters('administrators')[copyIndex()].identityResourceId]" }, - "tenantId": "[if(contains(parameters('administrators')[copyIndex()], 'tenantId'), createObject('value', parameters('administrators')[copyIndex()].tenantId), createObject('value', tenant().tenantId))]" + "tenantId": { + "value": "[coalesce(tryGet(parameters('administrators')[copyIndex()], 'tenantId'), tenant().tenantId)]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1041,8 +1047,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "166868353165081250" + "version": "0.30.3.12046", + "templateHash": "17380647846007156110" }, "name": "DBforMySQL Flexible Server Administrators", "description": "This module deploys a DBforMySQL Flexible Server Administrator.", From 6982118bd93999d39bcc5f1c01f762ebbfcbfada Mon Sep 17 00:00:00 2001 From: hundredacres Date: Thu, 10 Oct 2024 00:23:07 -0700 Subject: [PATCH 52/93] feat: New Module Microsoft.Fabric/capacities - `avm/res/fabric/capacity` (#3266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description New bicep module to manage the Azure Fabric Capacity resource. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.fabric.capacity](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.fabric.capacity.yml/badge.svg?branch=feat%2Favm%2Fissues%2F1192)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.fabric.capacity.yml)| ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [X] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.res.fabric.capacity.yml | 89 ++++++ avm/res/fabric/capacity/README.md | 290 ++++++++++++++++++ avm/res/fabric/capacity/main.bicep | 92 ++++++ avm/res/fabric/capacity/main.json | 148 +++++++++ .../tests/e2e/defaults/main.test.bicep | 51 +++ .../tests/e2e/waf-aligned/main.test.bicep | 52 ++++ avm/res/fabric/capacity/version.json | 7 + 9 files changed, 731 insertions(+) create mode 100644 .github/workflows/avm.res.fabric.capacity.yml create mode 100644 avm/res/fabric/capacity/README.md create mode 100644 avm/res/fabric/capacity/main.bicep create mode 100644 avm/res/fabric/capacity/main.json create mode 100644 avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/fabric/capacity/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a060083148..6655b13e89 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -72,6 +72,7 @@ /avm/res/event-grid/system-topic/ @Azure/avm-res-eventgrid-systemtopic-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/topic/ @Azure/avm-res-eventgrid-topic-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-hub/namespace/ @Azure/avm-res-eventhub-namespace-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/fabric/capacity/ @Azure/avm-res-fabric-capacity-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/health-bot/health-bot/ @Azure/avm-res-healthbot-healthbot-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/healthcare-apis/workspace/ @Azure/avm-res-healthcareapis-workspace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/hybrid-compute/machine/ @Azure/avm-res-hybridcompute-machine-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 610c26742c..b4ad2c6d81 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -107,6 +107,7 @@ body: - "avm/res/event-grid/system-topic" - "avm/res/event-grid/topic" - "avm/res/event-hub/namespace" + - "avm/res/fabric/capacity" - "avm/res/health-bot/health-bot" - "avm/res/healthcare-apis/workspace" - "avm/res/hybrid-compute/machine" diff --git a/.github/workflows/avm.res.fabric.capacity.yml b/.github/workflows/avm.res.fabric.capacity.yml new file mode 100644 index 0000000000..778c48160b --- /dev/null +++ b/.github/workflows/avm.res.fabric.capacity.yml @@ -0,0 +1,89 @@ +name: "avm.res.fabric.capacity" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.fabric.capacity.yml" + - "avm/res/fabric/capacity/**" + - "avm/res/fabric/capacity/topic/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/fabric/capacity" + workflowPath: ".github/workflows/avm.res.fabric.capacity.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/fabric/capacity/README.md b/avm/res/fabric/capacity/README.md new file mode 100644 index 0000000000..8cec8824cb --- /dev/null +++ b/avm/res/fabric/capacity/README.md @@ -0,0 +1,290 @@ +# Fabric Capacities `[Microsoft.Fabric/capacities]` + +This module deploys Fabric capacities, which provide the compute resources for all the experiences in Fabric. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Fabric/capacities` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates) | + +## 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/fabric/capacity:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [WAF-aligned](#example-2-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +
    + +via Bicep module + +```bicep +module capacity 'br/public:avm/res/fabric/capacity:' = { + name: 'capacityDeployment' + params: { + // Required parameters + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + name: 'fcmin001' + // 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 + "adminMembers": { + "value": [ + "mattschmitt@microsoft.com" + ] + }, + "name": { + "value": "fcmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/fabric/capacity:' + +// Required parameters +param adminMembers = [ + 'mattschmitt@microsoft.com' +] +param name = 'fcmin001' +// Non-required parameters +param location = '' +``` + +
    +

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

    + +via Bicep module + +```bicep +module capacity 'br/public:avm/res/fabric/capacity:' = { + name: 'capacityDeployment' + params: { + // Required parameters + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + name: 'fcwaf001' + // Non-required parameters + location: '' + skuName: 'F64' + } +} +``` + +
    +

    + +

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

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/fabric/capacity:' + +// Required parameters +param adminMembers = [ + 'mattschmitt@microsoft.com' +] +param name = 'fcwaf001' +// Non-required parameters +param location = '' +param skuName = 'F64' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`adminMembers`](#parameter-adminmembers) | array | List of admin members. Format: ["something@domain.com"]. | +| [`name`](#parameter-name) | string | Name of the resource to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`skuName`](#parameter-skuname) | string | SKU tier of the Fabric resource. | +| [`skuTier`](#parameter-skutier) | string | SKU name of the Fabric resource. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `adminMembers` + +List of admin members. Format: ["something@domain.com"]. + +- Required: Yes +- Type: array + +### Parameter: `name` + +Name of the resource to create. + +- 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: `skuName` + +SKU tier of the Fabric resource. + +- Required: No +- Type: string +- Default: `'F2'` +- Allowed: + ```Bicep + [ + 'F1024' + 'F128' + 'F16' + 'F2' + 'F2048' + 'F256' + 'F32' + 'F4' + 'F512' + 'F64' + 'F8' + ] + ``` + +### Parameter: `skuTier` + +SKU name of the Fabric resource. + +- Required: No +- Type: string +- Default: `'Fabric'` +- Allowed: + ```Bicep + [ + 'Fabric' + ] + ``` + +### 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 Fabric resource. | +| `resourceGroupName` | string | The name of the resource group the module was deployed to. | +| `resourceId` | string | The resource ID of the deployed Fabric 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/res/fabric/capacity/main.bicep b/avm/res/fabric/capacity/main.bicep new file mode 100644 index 0000000000..3e855ad580 --- /dev/null +++ b/avm/res/fabric/capacity/main.bicep @@ -0,0 +1,92 @@ +metadata name = 'Fabric Capacities' +metadata description = 'This module deploys Fabric capacities, which provide the compute resources for all the experiences in Fabric.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the resource to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@allowed([ + 'F2' + 'F4' + 'F8' + 'F16' + 'F32' + 'F64' + 'F128' + 'F256' + 'F512' + 'F1024' + 'F2048' +]) +@description('Optional. SKU tier of the Fabric resource.') +param skuName string = 'F2' + +@allowed(['Fabric']) +@description('Optional. SKU name of the Fabric resource.') +param skuTier string = 'Fabric' + +@description('Required. List of admin members. Format: ["something@domain.com"].') +param adminMembers array + +@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: '46d3xbcp.res.fabric-capacity.${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 fabricCapacity 'Microsoft.Fabric/capacities@2023-11-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: skuTier + } + properties: { + administration: { + members: adminMembers + } + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The name of the resource group the module was deployed to.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the deployed Fabric resource.') +output resourceId string = fabricCapacity.id + +@description('The name of the deployed Fabric resource.') +output name string = fabricCapacity.name + +@description('The location the resource was deployed into.') +output location string = fabricCapacity.location diff --git a/avm/res/fabric/capacity/main.json b/avm/res/fabric/capacity/main.json new file mode 100644 index 0000000000..c6d0daee58 --- /dev/null +++ b/avm/res/fabric/capacity/main.json @@ -0,0 +1,148 @@ +{ + "$schema": "https://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.3.12046", + "templateHash": "11718641793898572278" + }, + "name": "Fabric Capacities", + "description": "This module deploys Fabric capacities, which provide the compute resources for all the experiences in Fabric.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource 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." + } + }, + "skuName": { + "type": "string", + "defaultValue": "F2", + "allowedValues": [ + "F2", + "F4", + "F8", + "F16", + "F32", + "F64", + "F128", + "F256", + "F512", + "F1024", + "F2048" + ], + "metadata": { + "description": "Optional. SKU tier of the Fabric resource." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Fabric", + "allowedValues": [ + "Fabric" + ], + "metadata": { + "description": "Optional. SKU name of the Fabric resource." + } + }, + "adminMembers": { + "type": "array", + "metadata": { + "description": "Required. List of admin members. Format: [\"something@domain.com\"]." + } + }, + "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.fabric-capacity.{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" + } + } + } + } + }, + "fabricCapacity": { + "type": "Microsoft.Fabric/capacities", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "properties": { + "administration": { + "members": "[parameters('adminMembers')]" + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the module was deployed to." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed Fabric resource." + }, + "value": "[resourceId('Microsoft.Fabric/capacities', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed Fabric resource." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('fabricCapacity', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep b/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..a0057419f4 --- /dev/null +++ b/avm/res/fabric/capacity/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}-fabric-capacities-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'fcmin' + +@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 + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + } + } +] diff --git a/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep b/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..903ccd6b35 --- /dev/null +++ b/avm/res/fabric/capacity/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}-fabric-capacities-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'fcwaf' + +@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 + skuName: 'F64' + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + } + } +] diff --git a/avm/res/fabric/capacity/version.json b/avm/res/fabric/capacity/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/fabric/capacity/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From c767e2498a9b01b9c35ffd11e82304e2ea1602f7 Mon Sep 17 00:00:00 2001 From: "Menghua Chen (MSFT)" <111940661+Menghua1@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:34:18 +0800 Subject: [PATCH 53/93] feat: Add new ptn modules `azd/ml-hub-dependencies`. (#3241) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1227 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-hub-dependencies](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-hub-dependencies.yml/badge.svg?branch=ml-hub-dependencies)](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-hub-dependencies.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.ptn.azd.ml-hub-dependencies.yml | 88 + avm/ptn/azd/ml-hub-dependencies/README.md | 901 + avm/ptn/azd/ml-hub-dependencies/main.bicep | 482 + avm/ptn/azd/ml-hub-dependencies/main.json | 18738 ++++++++++++++++ .../tests/e2e/defaults/main.test.bicep | 49 + .../tests/e2e/max/main.test.bicep | 54 + avm/ptn/azd/ml-hub-dependencies/version.json | 7 + 9 files changed, 20321 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.ml-hub-dependencies.yml create mode 100644 avm/ptn/azd/ml-hub-dependencies/README.md create mode 100644 avm/ptn/azd/ml-hub-dependencies/main.bicep create mode 100644 avm/ptn/azd/ml-hub-dependencies/main.json create mode 100644 avm/ptn/azd/ml-hub-dependencies/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/ml-hub-dependencies/tests/e2e/max/main.test.bicep create mode 100644 avm/ptn/azd/ml-hub-dependencies/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6655b13e89..5ccd0ea12d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,6 +15,7 @@ /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/dev-ops/cicd-agents-and-runners/ @Azure/avm-ptn-devops-cicdagentsandrunners-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/finops-toolkit/finops-hub/ @Azure/avm-ptn-finopstoolkit-finopshub-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index b4ad2c6d81..486e96195c 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -50,6 +50,7 @@ body: - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" + - "avm/ptn/azd/ml-hub-dependencies" - "avm/ptn/deployment-script/import-image-to-acr" - "avm/ptn/dev-ops/cicd-agents-and-runners" - "avm/ptn/finops-toolkit/finops-hub" diff --git a/.github/workflows/avm.ptn.azd.ml-hub-dependencies.yml b/.github/workflows/avm.ptn.azd.ml-hub-dependencies.yml new file mode 100644 index 0000000000..fc862654f2 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.ml-hub-dependencies.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.ml-hub-dependencies" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.ml-hub-dependencies" + - "avm/ptn/azd/ml-hub-dependencies/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/ml-hub-dependencies" + workflowPath: ".github/workflows/avm.ptn.azd.ml-hub-dependencies.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit \ No newline at end of file diff --git a/avm/ptn/azd/ml-hub-dependencies/README.md b/avm/ptn/azd/ml-hub-dependencies/README.md new file mode 100644 index 0000000000..7a9f689c43 --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/README.md @@ -0,0 +1,901 @@ +# Azd Azure Machine Learning Dependencies `[Azd/MlHubDependencies]` + +Creates all the dependencies required for a Machine Learning Service. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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.CognitiveServices/accounts` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts) | +| `Microsoft.CognitiveServices/accounts/deployments` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts/deployments) | +| `Microsoft.ContainerRegistry/registries` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries) | +| `Microsoft.ContainerRegistry/registries/cacheRules` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/cacheRules) | +| `Microsoft.ContainerRegistry/registries/credentialSets` | [2023-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/credentialSets) | +| `Microsoft.ContainerRegistry/registries/replications` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/replications) | +| `Microsoft.ContainerRegistry/registries/scopeMaps` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/scopeMaps) | +| `Microsoft.ContainerRegistry/registries/webhooks` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/webhooks) | +| `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) | +| `Microsoft.KeyVault/vaults` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults) | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-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-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `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-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `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` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-01/workspaces) | +| `Microsoft.OperationalInsights/workspaces/dataExports` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataExports) | +| `Microsoft.OperationalInsights/workspaces/dataSources` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataSources) | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedServices) | +| `Microsoft.OperationalInsights/workspaces/linkedStorageAccounts` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedStorageAccounts) | +| `Microsoft.OperationalInsights/workspaces/savedSearches` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/savedSearches) | +| `Microsoft.OperationalInsights/workspaces/storageInsightConfigs` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/storageInsightConfigs) | +| `Microsoft.OperationalInsights/workspaces/tables` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-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.Portal/dashboards` | [2020-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Portal/2020-09-01-preview/dashboards) | +| `Microsoft.Search/searchServices` | [2024-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2024-03-01-preview/searchServices) | +| `Microsoft.Search/searchServices/sharedPrivateLinkResources` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2023-11-01/searchServices/sharedPrivateLinkResources) | +| `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-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/ptn/azd/ml-hub-dependencies:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module mlHubDependencies 'br/public:avm/ptn/azd/ml-hub-dependencies:' = { + name: 'mlHubDependenciesDeployment' + params: { + // Required parameters + cognitiveServicesName: 'cog07hubdmin' + keyVaultName: 'key07hubdmin' + storageAccountName: 'st07hubdmin' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "cognitiveServicesName": { + "value": "cog07hubdmin" + }, + "keyVaultName": { + "value": "key07hubdmin" + }, + "storageAccountName": { + "value": "st07hubdmin" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-hub-dependencies:' + +// Required parameters +param cognitiveServicesName = 'cog07hubdmin' +param keyVaultName = 'key07hubdmin' +param storageAccountName = 'st07hubdmin' +``` + +
    +

    + +### Example 2: _Using large parameter set_ + +This instance deploys the module using large parameters. + + +

    + +via Bicep module + +```bicep +module mlHubDependencies 'br/public:avm/ptn/azd/ml-hub-dependencies:' = { + name: 'mlHubDependenciesDeployment' + params: { + // Required parameters + cognitiveServicesName: 'cs08mhdpmax' + keyVaultName: 'kv08mhdpmax' + storageAccountName: 'sa08mhdpmax' + // Non-required parameters + applicationInsightsDashboardName: 'aid08mhdpmax' + applicationInsightsName: 'ai08mhdpmax' + containerRegistryName: 'cr08mhdpmax' + logAnalyticsName: 'log08mhdpmax' + searchServiceName: 'sea08mhdpmax' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "cognitiveServicesName": { + "value": "cs08mhdpmax" + }, + "keyVaultName": { + "value": "kv08mhdpmax" + }, + "storageAccountName": { + "value": "sa08mhdpmax" + }, + // Non-required parameters + "applicationInsightsDashboardName": { + "value": "aid08mhdpmax" + }, + "applicationInsightsName": { + "value": "ai08mhdpmax" + }, + "containerRegistryName": { + "value": "cr08mhdpmax" + }, + "logAnalyticsName": { + "value": "log08mhdpmax" + }, + "searchServiceName": { + "value": "sea08mhdpmax" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-hub-dependencies:' + +// Required parameters +param cognitiveServicesName = 'cs08mhdpmax' +param keyVaultName = 'kv08mhdpmax' +param storageAccountName = 'sa08mhdpmax' +// Non-required parameters +param applicationInsightsDashboardName = 'aid08mhdpmax' +param applicationInsightsName = 'ai08mhdpmax' +param containerRegistryName = 'cr08mhdpmax' +param logAnalyticsName = 'log08mhdpmax' +param searchServiceName = 'sea08mhdpmax' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cognitiveServicesName`](#parameter-cognitiveservicesname) | string | Name of the OpenAI cognitive services. | +| [`keyVaultName`](#parameter-keyvaultname) | string | Name of the key vault. | +| [`storageAccountName`](#parameter-storageaccountname) | string | Name of the storage account. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`. | + +**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. | +| [`applicationInsightsDashboardName`](#parameter-applicationinsightsdashboardname) | string | The resource portal dashboards name. | +| [`applicationInsightsName`](#parameter-applicationinsightsname) | string | The resource insights components name. | +| [`authOptions`](#parameter-authoptions) | object | Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true. | +| [`blobServices`](#parameter-blobservices) | object | Blob service and containers to deploy. | +| [`cmkEnforcement`](#parameter-cmkenforcement) | string | Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys. | +| [`cognitiveServicesCustomSubDomainName`](#parameter-cognitiveservicescustomsubdomainname) | string | The custom subdomain name used to access the API. Defaults to the value of the name parameter. | +| [`cognitiveServicesDeployments`](#parameter-cognitiveservicesdeployments) | array | Array of deployments about cognitive service accounts to create. | +| [`cognitiveServicesDisableLocalAuth`](#parameter-cognitiveservicesdisablelocalauth) | bool | Allow only Azure AD authentication. Should be enabled for security reasons. | +| [`cognitiveServicesKind`](#parameter-cognitiveserviceskind) | string | Kind of the Cognitive Services. | +| [`cognitiveServicesNetworkAcls`](#parameter-cognitiveservicesnetworkacls) | object | A collection of rules governing the accessibility from specific network locations. | +| [`cognitiveServicesPublicNetworkAccess`](#parameter-cognitiveservicespublicnetworkaccess) | 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. | +| [`cognitiveServicesSku`](#parameter-cognitiveservicessku) | string | SKU of the Cognitive Services resource. | +| [`containerRegistryName`](#parameter-containerregistryname) | string | Name of the container registry. | +| [`dataRetention`](#parameter-dataretention) | int | Number of days data will be retained for. | +| [`disableLocalAuth`](#parameter-disablelocalauth) | bool | When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined. | +| [`dnsEndpointType`](#parameter-dnsendpointtype) | string | Allows you to specify the type of endpoint in the storage account. 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. | +| [`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. | +| [`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. | +| [`enableVaultForTemplateDeployment`](#parameter-enablevaultfortemplatedeployment) | bool | Specifies if the vault is enabled for a template deployment. | +| [`fileServices`](#parameter-fileservices) | object | File service and shares to deploy. | +| [`hostingMode`](#parameter-hostingmode) | string | Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'. | +| [`keyVaultSku`](#parameter-keyvaultsku) | string | Specifies the SKU for the vault. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`logAnalyticsName`](#parameter-loganalyticsname) | string | The resource operational insights workspaces name. | +| [`logAnalyticsSkuName`](#parameter-loganalyticsskuname) | string | The name of the SKU. | +| [`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. | +| [`networkRuleSet`](#parameter-networkruleset) | object | Network specific rules that determine how the Azure Cognitive Search service may be reached. | +| [`partitionCount`](#parameter-partitioncount) | int | The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for the storage account. 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. | +| [`registryAcrSku`](#parameter-registryacrsku) | string | Tier of your Azure container registry. | +| [`registryPublicNetworkAccess`](#parameter-registrypublicnetworkaccess) | string | Public network access setting. | +| [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. | +| [`searchServiceName`](#parameter-searchservicename) | string | Name of the Azure Cognitive Search service. | +| [`searchServicePublicNetworkAccess`](#parameter-searchservicepublicnetworkaccess) | string | This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method. | +| [`searchServiceSku`](#parameter-searchservicesku) | string | Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits. | +| [`semanticSearch`](#parameter-semanticsearch) | string | Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. | +| [`tableServices`](#parameter-tableservices) | object | Table service and tables to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `cognitiveServicesName` + +Name of the OpenAI cognitive services. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +Name of the key vault. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +Name of the storage account. + +- Required: Yes +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`. + +- 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: `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: `True` + +### Parameter: `applicationInsightsDashboardName` + +The resource portal dashboards name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `applicationInsightsName` + +The resource insights components name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `authOptions` + +Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `blobServices` + +Blob service and containers to deploy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + containerDeleteRetentionPolicyDays: 7 + containers: [ + { + name: 'default' + } + ] + corsRules: [ + { + allowedHeaders: [ + '*' + ] + allowedMethods: [ + 'DELETE' + 'GET' + 'HEAD' + 'OPTIONS' + 'PATCH' + 'POST' + 'PUT' + ] + allowedOrigins: [ + 'https://*.ai.azure.com' + 'https://*.ml.azure.com' + 'https://ai.azure.com' + 'https://ml.azure.com' + 'https://mlworkspace.azure.ai' + 'https://mlworkspace.azureml-test.net' + 'https://mlworkspacecanary.azure.ai' + ] + exposedHeaders: [ + '*' + ] + maxAgeInSeconds: 1800 + } + ] + deleteRetentionPolicyAllowPermanentDelete: true + deleteRetentionPolicyDays: 6 + deleteRetentionPolicyEnabled: true + } + ``` + +### Parameter: `cmkEnforcement` + +Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys. + +- Required: No +- Type: string +- Default: `'Unspecified'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + 'Unspecified' + ] + ``` + +### Parameter: `cognitiveServicesCustomSubDomainName` + +The custom subdomain name used to access the API. Defaults to the value of the name parameter. + +- Required: No +- Type: string +- Default: `[parameters('cognitiveServicesName')]` + +### Parameter: `cognitiveServicesDeployments` + +Array of deployments about cognitive service accounts to create. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `cognitiveServicesDisableLocalAuth` + +Allow only Azure AD authentication. Should be enabled for security reasons. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `cognitiveServicesKind` + +Kind of the Cognitive Services. + +- Required: No +- Type: string +- Default: `'AIServices'` + +### Parameter: `cognitiveServicesNetworkAcls` + +A collection of rules governing the accessibility from specific network locations. + +- Required: No +- Type: object +- Default: + ```Bicep + { + defaultAction: 'Allow' + } + ``` + +### Parameter: `cognitiveServicesPublicNetworkAccess` + +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: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `cognitiveServicesSku` + +SKU of the Cognitive Services resource. + +- Required: No +- Type: string +- Default: `'S0'` + +### Parameter: `containerRegistryName` + +Name of the container registry. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `dataRetention` + +Number of days data will be retained for. + +- Required: No +- Type: int +- Default: `30` + +### Parameter: `disableLocalAuth` + +When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `dnsEndpointType` + +Allows you to specify the type of endpoint in the storage account. 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: `'Standard'` +- Allowed: + ```Bicep + [ + '' + 'AzureDnsZone' + 'Standard' + ] + ``` + +### Parameter: `enablePurgeProtection` + +Provide 'true' to enable Key Vault's purge protection feature. + +- Required: No +- Type: bool +- Default: `False` + +### 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: `False` + +### 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: `False` + +### Parameter: `enableVaultForTemplateDeployment` + +Specifies if the vault is enabled for a template deployment. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `fileServices` + +File service and shares to deploy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: 'default' + } + ``` + +### Parameter: `hostingMode` + +Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'. + +- Required: No +- Type: string +- Default: `'default'` +- Allowed: + ```Bicep + [ + 'default' + 'highDensity' + ] + ``` + +### Parameter: `keyVaultSku` + +Specifies the SKU for the vault. + +- Required: No +- Type: string +- Default: `'standard'` +- Allowed: + ```Bicep + [ + 'premium' + 'standard' + ] + ``` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `logAnalyticsName` + +The resource operational insights workspaces name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `logAnalyticsSkuName` + +The name of the SKU. + +- Required: No +- Type: string +- Default: `'PerGB2018'` +- Allowed: + ```Bicep + [ + 'CapacityReservation' + 'Free' + 'LACluster' + 'PerGB2018' + 'PerNode' + 'Premium' + 'Standalone' + 'Standard' + ] + ``` + +### 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 +- Default: + ```Bicep + { + bypass: 'AzureServices' + defaultAction: 'Allow' + } + ``` + +### Parameter: `networkRuleSet` + +Network specific rules that determine how the Azure Cognitive Search service may be reached. + +- Required: No +- Type: object +- Default: + ```Bicep + { + bypass: 'None' + ipRules: [] + } + ``` + +### Parameter: `partitionCount` + +The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for the storage account. 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: `'Enabled'` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `queueServices` + +Queue service and queues to create. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: 'default' + } + ``` + +### Parameter: `registryAcrSku` + +Tier of your Azure container registry. + +- Required: No +- Type: string +- Default: `'Basic'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `registryPublicNetworkAccess` + +Public network access setting. + +- Required: No +- Type: string +- Default: `'Enabled'` + +### Parameter: `replicaCount` + +The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `searchServiceName` + +Name of the Azure Cognitive Search service. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `searchServicePublicNetworkAccess` + +This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `searchServiceSku` + +Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits. + +- Required: No +- Type: string +- Default: `'standard'` +- Allowed: + ```Bicep + [ + 'basic' + 'free' + 'standard' + 'standard2' + 'standard3' + 'storage_optimized_l1' + 'storage_optimized_l2' + ] + ``` + +### Parameter: `semanticSearch` + +Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. + +- Required: No +- Type: string +- Default: `'disabled'` +- Allowed: + ```Bicep + [ + 'disabled' + 'free' + 'standard' + ] + ``` + +### Parameter: `tableServices` + +Table service and tables to create. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: 'default' + } + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + "key1": "value1" + "key2": "value2" + } + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `applicationInsightsConnectionString` | string | The connection string of the application insights. | +| `applicationInsightsInstrumentationKey` | string | The instrumentation key of the application insights. | +| `applicationInsightsName` | string | The name of the application insights. | +| `applicationInsightsResourceId` | string | The resource ID of the application insights. | +| `cognitiveServicesEndpoint` | string | The endpoint of the cognitive services. | +| `cognitiveServicesName` | string | The name of the cognitive services. | +| `cognitiveServicesResourceId` | string | The resource ID of the cognitive services. | +| `containerRegistryEndpoint` | string | The endpoint of the container registry. | +| `containerRegistryName` | string | The name of the container registry. | +| `containerRegistryResourceId` | string | The resource ID of the container registry. | +| `keyVaultEndpoint` | string | The endpoint of the key vault. | +| `keyVaultName` | string | The name of the key vault. | +| `keyVaultResourceId` | string | The resource ID of the key vault. | +| `logAnalyticsWorkspaceName` | string | The name of the loganalytics workspace. | +| `logAnalyticsWorkspaceResourceId` | string | The resource ID of the loganalytics workspace. | +| `resourceGroupName` | string | The name of the resource group the module was deployed to. | +| `searchServiceEndpoint` | string | The endpoint of the search service. | +| `searchServiceName` | string | The name of the search service. | +| `searchServiceResourceId` | string | The resource ID of the search service. | +| `storageAccountName` | string | The name of the storage account. | +| `storageAccountResourceId` | string | The resource ID of the storage account. | +| `systemAssignedMiPrincipalId` | string | The system assigned mi principal Id key of the search 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/ptn/azd/insights-dashboard:0.1.0` | Remote reference | +| `br/public:avm/res/cognitive-services/account:0.7.0` | Remote reference | +| `br/public:avm/res/container-registry/registry:0.4.0` | Remote reference | +| `br/public:avm/res/key-vault/vault:0.7.1` | Remote reference | +| `br/public:avm/res/operational-insights/workspace:0.6.0` | Remote reference | +| `br/public:avm/res/search/search-service:0.6.0` | Remote reference | +| `br/public:avm/res/storage/storage-account:0.9.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/ptn/azd/ml-hub-dependencies/main.bicep b/avm/ptn/azd/ml-hub-dependencies/main.bicep new file mode 100644 index 0000000000..d35212616c --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/main.bicep @@ -0,0 +1,482 @@ +metadata name = 'Azd Azure Machine Learning Dependencies' +metadata description = '''Creates all the dependencies required for a Machine Learning Service. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. The resource portal dashboards name.') +param applicationInsightsDashboardName string = '' + +@description('Optional. The resource insights components name.') +param applicationInsightsName string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. The resource operational insights workspaces name.') +param logAnalyticsName string = '' + +@description('Required. Name of the key vault.') +param keyVaultName string + +@description('Required. Name of the storage account.') +param storageAccountName string + +@description('Required. Name of the OpenAI cognitive services.') +param cognitiveServicesName string + +@description('Optional. Name of the container registry.') +param containerRegistryName string = '' + +@description('Optional. Name of the Azure Cognitive Search service.') +param searchServiceName string = '' + +@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 = true + +@description('Optional. Allows you to specify the type of endpoint in the storage account. 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 = 'Standard' + +@description('Optional. Whether or not public network access is allowed for the storage account. 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 = 'Enabled' + +@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 object = { + bypass: 'AzureServices' + defaultAction: 'Allow' +} + +@description('Optional. Blob service and containers to deploy.') +param blobServices object = { + containers: [ + { + name: 'default' + } + ] + corsRules: [ + { + allowedOrigins: [ + 'https://mlworkspace.azure.ai' + 'https://ml.azure.com' + 'https://*.ml.azure.com' + 'https://ai.azure.com' + 'https://*.ai.azure.com' + 'https://mlworkspacecanary.azure.ai' + 'https://mlworkspace.azureml-test.net' + ] + allowedMethods: [ + 'GET' + 'HEAD' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + 'PATCH' + ] + maxAgeInSeconds: 1800 + exposedHeaders: [ + '*' + ] + allowedHeaders: [ + '*' + ] + } + ] + deleteRetentionPolicyEnabled: true + containerDeleteRetentionPolicyDays: 7 + deleteRetentionPolicyDays: 6 + deleteRetentionPolicyAllowPermanentDelete: true +} + +@description('Optional. File service and shares to deploy.') +param fileServices object = { + name: 'default' +} + +@description('Optional. Queue service and queues to create.') +param queueServices object = { + name: 'default' +} + +@description('Optional. Table service and tables to create.') +param tableServices object = { + name: 'default' +} + +@description('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +@description('Optional. Kind of the Cognitive Services.') +param cognitiveServicesKind string = 'AIServices' + +@description('Optional. Array of deployments about cognitive service accounts to create.') +param cognitiveServicesDeployments array = [] + +@description('Optional. The custom subdomain name used to access the API. Defaults to the value of the name parameter.') +param cognitiveServicesCustomSubDomainName string = cognitiveServicesName + +@description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') +param cognitiveServicesDisableLocalAuth bool = false + +@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 cognitiveServicesPublicNetworkAccess string = 'Disabled' + +@description('Optional. A collection of rules governing the accessibility from specific network locations.') +param cognitiveServicesNetworkAcls object = { + defaultAction: 'Allow' +} + +@description('Optional. SKU of the Cognitive Services resource.') +param cognitiveServicesSku string = 'S0' + +@description('Optional. Tier of your Azure container registry.') +@allowed([ + 'Basic' + 'Premium' + 'Standard' +]) +param registryAcrSku string = 'Basic' + +@description('Optional. Public network access setting.') +param registryPublicNetworkAccess string = 'Enabled' + +@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 = false + +@description('Optional. Specifies if the vault is enabled for deployment by script or compute.') +param enableVaultForDeployment bool = false + +@description('Optional. Specifies if the vault is enabled for a template deployment.') +param enableVaultForTemplateDeployment bool = false + +@description('Optional. Provide \'true\' to enable Key Vault\'s purge protection feature.') +param enablePurgeProtection bool = false + +@description('Optional. Specifies the SKU for the vault.') +@allowed([ + 'premium' + 'standard' +]) +param keyVaultSku string = 'standard' + +@description('Optional. The name of the SKU.') +@allowed([ + 'CapacityReservation' + 'Free' + 'LACluster' + 'PerGB2018' + 'PerNode' + 'Premium' + 'Standalone' + 'Standard' +]) +param logAnalyticsSkuName string = 'PerGB2018' + +@description('Optional. Number of days data will be retained for.') +@minValue(0) +@maxValue(730) +param dataRetention int = 30 + +@description('Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if \'disableLocalAuth\' is set to true.') +param authOptions object = {} + +@description('Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if \'authOptions\' are defined.') +param disableLocalAuth bool = false + +@description('Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys.') +@allowed([ + 'Disabled' + 'Enabled' + 'Unspecified' +]) +param cmkEnforcement string = 'Unspecified' + +@description('Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either \'default\' or \'highDensity\'. For all other SKUs, this value must be \'default\'.') +@allowed([ + 'default' + 'highDensity' +]) +param hostingMode string = 'default' + +@description('Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached.') +param networkRuleSet object = { + bypass: 'None' + ipRules: [] +} + +@description('Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For \'standard3\' services with hostingMode set to \'highDensity\', the allowed values are between 1 and 3.') +@minValue(1) +@maxValue(12) +param partitionCount int = 1 + +@description('Optional. This value can be set to \'Enabled\' to avoid breaking changes on existing customer resources and templates. If set to \'Disabled\', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param searchServicePublicNetworkAccess string = 'Enabled' + +@description('Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU.') +@minValue(1) +@maxValue(12) +param replicaCount int = 1 + +@allowed([ + 'disabled' + 'free' + 'standard' +]) +@description('Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations.') +param semanticSearch string = 'disabled' + +@description('Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits.') +@allowed([ + 'basic' + 'free' + 'standard' + 'standard2' + 'standard3' + 'storage_optimized_l1' + 'storage_optimized_l2' +]) +param searchServiceSku string = 'standard' + +@description('Conditional. The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`.') +param managedIdentities managedIdentitiesType? + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-mlhubdependencies.${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 keyVault 'br/public:avm/res/key-vault/vault:0.7.1' = { + name: '${uniqueString(deployment().name, location)}-keyvault' + params: { + name: keyVaultName + location: location + tags: tags + enableRbacAuthorization: enableRbacAuthorization + enableVaultForDeployment: enableVaultForDeployment + enableVaultForTemplateDeployment: enableVaultForTemplateDeployment + enablePurgeProtection: enablePurgeProtection + sku: keyVaultSku + enableTelemetry: enableTelemetry + } +} + +module storageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: '${uniqueString(deployment().name, location)}-storage' + params: { + name: storageAccountName + location: location + tags: tags + allowBlobPublicAccess: allowBlobPublicAccess + dnsEndpointType: dnsEndpointType + publicNetworkAccess: publicNetworkAccess + networkAcls: networkAcls + blobServices: blobServices + fileServices: fileServices + queueServices: queueServices + tableServices: tableServices + enableTelemetry: enableTelemetry + } +} + +module cognitiveServices 'br/public:avm/res/cognitive-services/account:0.7.0' = { + name: '${uniqueString(deployment().name, location)}-cognitive' + params: { + name: cognitiveServicesName + location: location + tags: tags + kind: cognitiveServicesKind + customSubDomainName: cognitiveServicesCustomSubDomainName + publicNetworkAccess: cognitiveServicesPublicNetworkAccess + networkAcls: cognitiveServicesNetworkAcls + disableLocalAuth: cognitiveServicesDisableLocalAuth + sku: cognitiveServicesSku + deployments: cognitiveServicesDeployments + enableTelemetry: enableTelemetry + } +} + +module logAnalytics 'br/public:avm/res/operational-insights/workspace:0.6.0' = if (!empty(logAnalyticsName)) { + name: '${uniqueString(deployment().name, location)}-loganalytics' + params: { + name: logAnalyticsName + location: location + tags: tags + dataRetention: dataRetention + skuName: logAnalyticsSkuName + enableTelemetry: enableTelemetry + } +} + +module applicationInsights 'br/public:avm/ptn/azd/insights-dashboard:0.1.0' = if (!empty(applicationInsightsName) && !empty(logAnalyticsName)) { + name: '${uniqueString(deployment().name, location)}-insights' + params: { + location: location + tags: tags + name: applicationInsightsName + dashboardName: applicationInsightsDashboardName + logAnalyticsWorkspaceResourceId: !empty(logAnalyticsName) ? logAnalytics.outputs.resourceId : '' + enableTelemetry: enableTelemetry + } +} + +module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = if (!empty(containerRegistryName)) { + name: '${uniqueString(deployment().name, location)}-registry' + params: { + name: containerRegistryName + acrSku: registryAcrSku + tags: tags + location: location + publicNetworkAccess: registryPublicNetworkAccess + enableTelemetry: enableTelemetry + } +} + +module searchService 'br/public:avm/res/search/search-service:0.6.0' = if (!empty(searchServiceName)) { + name: '${uniqueString(deployment().name, location)}-searchservice' + params: { + name: searchServiceName + location: location + tags: tags + authOptions: authOptions + disableLocalAuth: disableLocalAuth + cmkEnforcement: cmkEnforcement + hostingMode: hostingMode + networkRuleSet: networkRuleSet + partitionCount: partitionCount + publicNetworkAccess: searchServicePublicNetworkAccess + replicaCount: replicaCount + semanticSearch: semanticSearch + sku: searchServiceSku + managedIdentities: managedIdentities + enableTelemetry: enableTelemetry + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The name of the resource group the module was deployed to.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the key vault.') +output keyVaultResourceId string = keyVault.outputs.resourceId + +@description('The name of the key vault.') +output keyVaultName string = keyVault.outputs.name + +@description('The endpoint of the key vault.') +output keyVaultEndpoint string = keyVault.outputs.uri + +@description('The resource ID of the storage account.') +output storageAccountResourceId string = storageAccount.outputs.resourceId + +@description('The name of the storage account.') +output storageAccountName string = storageAccount.outputs.name + +@description('The resource ID of the container registry.') +output containerRegistryResourceId string = !empty(containerRegistryName) ? containerRegistry.outputs.resourceId : '' + +@description('The name of the container registry.') +output containerRegistryName string = !empty(containerRegistryName) ? containerRegistry.outputs.name : '' + +@description('The endpoint of the container registry.') +output containerRegistryEndpoint string = !empty(containerRegistryName) ? containerRegistry.outputs.loginServer : '' + +@description('The resource ID of the application insights.') +output applicationInsightsResourceId string = !empty(applicationInsightsName) ? applicationInsights.outputs.applicationInsightsResourceId : '' + +@description('The name of the application insights.') +output applicationInsightsName string = !empty(applicationInsightsName) ? applicationInsights.outputs.applicationInsightsName : '' + +@description('The resource ID of the loganalytics workspace.') +output logAnalyticsWorkspaceResourceId string = !empty(logAnalyticsName) ? logAnalytics.outputs.resourceId : '' + +@description('The name of the loganalytics workspace.') +output logAnalyticsWorkspaceName string = !empty(logAnalyticsName) ? logAnalytics.outputs.name : '' + +@description('The resource ID of the cognitive services.') +output cognitiveServicesResourceId string = cognitiveServices.outputs.resourceId + +@description('The name of the cognitive services.') +output cognitiveServicesName string = cognitiveServices.outputs.name + +@description('The endpoint of the cognitive services.') +output cognitiveServicesEndpoint string = cognitiveServices.outputs.endpoint + +@description('The resource ID of the search service.') +output searchServiceResourceId string = !empty(searchServiceName) ? searchService.outputs.resourceId : '' + +@description('The name of the search service.') +output searchServiceName string = !empty(searchServiceName) ? searchService.outputs.name : '' + +@description('The endpoint of the search service.') +output searchServiceEndpoint string = !empty(searchServiceName) ? 'https://${searchService.outputs.name}.search.windows.net/' : '' + +@description('The connection string of the application insights.') +output applicationInsightsConnectionString string = !empty(applicationInsightsName) ? applicationInsights.outputs.applicationInsightsConnectionString : '' + +@description('The instrumentation key of the application insights.') +output applicationInsightsInstrumentationKey string = !empty(applicationInsightsName) ? applicationInsights.outputs.applicationInsightsInstrumentationKey : '' + +@description('The system assigned mi principal Id key of the search service.') +output systemAssignedMiPrincipalId string = !empty(searchServiceName) ? searchService.outputs.systemAssignedMIPrincipalId : '' + +// ================ // +// 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. Required if a user assigned identity is used for encryption.') + userAssignedResourceIds: string[]? +}? diff --git a/avm/ptn/azd/ml-hub-dependencies/main.json b/avm/ptn/azd/ml-hub-dependencies/main.json new file mode 100644 index 0000000000..4a195bc5a7 --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/main.json @@ -0,0 +1,18738 @@ +{ + "$schema": "https://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": "7687704138266254216" + }, + "name": "Azd Azure Machine Learning Dependencies", + "description": "Creates all the dependencies required for a Machine Learning Service.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "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. Required if a user assigned identity is used for encryption." + } + } + }, + "nullable": true + } + }, + "parameters": { + "applicationInsightsDashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "applicationInsightsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource insights components name." + } + }, + "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." + } + }, + "logAnalyticsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource operational insights workspaces name." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. Name of the key vault." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Name of the storage account." + } + }, + "cognitiveServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the OpenAI cognitive services." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the container registry." + } + }, + "searchServiceName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the Azure Cognitive Search service." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": 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." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint in the storage account. 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." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for the storage account. 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." + } + }, + "networkAcls": { + "type": "object", + "defaultValue": { + "bypass": "AzureServices", + "defaultAction": "Allow" + }, + "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." + } + }, + "blobServices": { + "type": "object", + "defaultValue": { + "containers": [ + { + "name": "default" + } + ], + "corsRules": [ + { + "allowedOrigins": [ + "https://mlworkspace.azure.ai", + "https://ml.azure.com", + "https://*.ml.azure.com", + "https://ai.azure.com", + "https://*.ai.azure.com", + "https://mlworkspacecanary.azure.ai", + "https://mlworkspace.azureml-test.net" + ], + "allowedMethods": [ + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "OPTIONS", + "PATCH" + ], + "maxAgeInSeconds": 1800, + "exposedHeaders": [ + "*" + ], + "allowedHeaders": [ + "*" + ] + } + ], + "deleteRetentionPolicyEnabled": true, + "containerDeleteRetentionPolicyDays": 7, + "deleteRetentionPolicyDays": 6, + "deleteRetentionPolicyAllowPermanentDelete": true + }, + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + }, + "cognitiveServicesKind": { + "type": "string", + "defaultValue": "AIServices", + "metadata": { + "description": "Optional. Kind of the Cognitive Services." + } + }, + "cognitiveServicesDeployments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "cognitiveServicesCustomSubDomainName": { + "type": "string", + "defaultValue": "[parameters('cognitiveServicesName')]", + "metadata": { + "description": "Optional. The custom subdomain name used to access the API. Defaults to the value of the name parameter." + } + }, + "cognitiveServicesDisableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "cognitiveServicesPublicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "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." + } + }, + "cognitiveServicesNetworkAcls": { + "type": "object", + "defaultValue": { + "defaultAction": "Allow" + }, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "cognitiveServicesSku": { + "type": "string", + "defaultValue": "S0", + "metadata": { + "description": "Optional. SKU of the Cognitive Services resource." + } + }, + "registryAcrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "registryPublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Optional. Public network access setting." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": false, + "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." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "keyVaultSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "logAnalyticsSkuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 30, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "authOptions": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default", + "highDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "networkRuleSet": { + "type": "object", + "defaultValue": { + "bypass": "None", + "ipRules": [] + }, + "metadata": { + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "searchServicePublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "searchServiceSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "nullable": true, + "metadata": { + "description": "Conditional. The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-mlhubdependencies.{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.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableRbacAuthorization": { + "value": "[parameters('enableRbacAuthorization')]" + }, + "enableVaultForDeployment": { + "value": "[parameters('enableVaultForDeployment')]" + }, + "enableVaultForTemplateDeployment": { + "value": "[parameters('enableVaultForTemplateDeployment')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "sku": { + "value": "[parameters('keyVaultSku')]" + }, + "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.29.47.4906", + "templateHash": "6878673228466609441" + }, + "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": { + "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." + } + }, + "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": "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 (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.keyvault-vault.{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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "7494731697751039419" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "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.29.47.4906", + "templateHash": "4990258423482296566" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "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 + } + }, + "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": { + "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 (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')]" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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'))]" + }, + "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.29.47.4906", + "templateHash": "10436564794447478489" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "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 + } + }, + "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": { + "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 (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())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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": { + "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], '2020-06-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]" + } + } + } + } + }, + "storageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-storage', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": "[parameters('allowBlobPublicAccess')]" + }, + "dnsEndpointType": { + "value": "[parameters('dnsEndpointType')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "networkAcls": { + "value": "[parameters('networkAcls')]" + }, + "blobServices": { + "value": "[parameters('blobServices')]" + }, + "fileServices": { + "value": "[parameters('fileServices')]" + }, + "queueServices": { + "value": "[parameters('queueServices')]" + }, + "tableServices": { + "value": "[parameters('tableServices')]" + }, + "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.28.1.47646", + "templateHash": "3958760216991467865" + }, + "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 + }, + "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": { + "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 + }, + "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." + } + }, + "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." + } + } + } + }, + "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." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "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." + } + }, + "localUsers": { + "type": "array", + "defaultValue": [], + "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": { + "$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." + } + }, + "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())]", + "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 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 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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.9.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" + } + } + } + } + }, + "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'))), 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", + "cMKUserAssignedIdentity" + ] + }, + "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(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts', 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": [ + "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], '2020-06-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": [ + "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.28.1.47646", + "templateHash": "9473195527943694039" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy.", + "owner": "Azure/module-maintainers" + }, + "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(parameters('localUsers'))]" + }, + "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": "[parameters('localUsers')[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[parameters('localUsers')[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[parameters('localUsers')[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[parameters('localUsers')[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(parameters('localUsers')[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.28.1.47646", + "templateHash": "14968464858285923305" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "sshAuthorizedKeysType": { + "type": "secureObject", + "properties": { + "secureList": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "string", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + } + }, + "metadata": { + "description": "Optional. The list of SSH authorized keys." + } + } + }, + "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", + "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", + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "$ref": "#/definitions/sshAuthorizedKeysType", + "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": "[tryGet(parameters('sshAuthorizedKeys'), 'secureList')]" + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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.28.1.47646", + "templateHash": "2306287879023715578" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob 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." + } + }, + "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", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies CORS rules for the Blob service. You can include up to five CorsRule elements in the request. If no CorsRule elements are included in the request body, all CORS rules will be deleted, and CORS will be disabled for the Blob service." + } + }, + "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": 6, + "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": { + "$ref": "#/definitions/diagnosticSettingType", + "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": { + "corsRules": "[parameters('corsRules')]" + }, + "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')]" + }, + "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.28.1.47646", + "templateHash": "7045309160947869799" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container.", + "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." + } + }, + "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", + "defaultValue": false, + "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": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "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')]", + "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 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'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "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'), 'default', parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", + "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')]" + }, + "dependsOn": [ + "storageAccount::blobServices" + ] + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', 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": [ + "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.28.1.47646", + "templateHash": "2543276032744560941" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy.", + "owner": "Azure/module-maintainers" + }, + "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", + "storageAccount" + ] + } + }, + "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'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "7463227074634701879" + }, + "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')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "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.28.1.47646", + "templateHash": "1342480740201032357" + }, + "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'))]", + "dependsOn": [ + "storageAccount" + ] + }, + "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')]" + }, + "dependsOn": [ + "storageAccount::fileService" + ] + }, + "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.28.1.47646", + "templateHash": "8779226603522513073" + } + }, + "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" + ] + }, + "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')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "10678250016540336570" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue 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." + } + }, + "queues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "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": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "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.28.1.47646", + "templateHash": "13487964166280180730" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue.", + "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." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Required. A name-value pair that represents queue metadata." + } + }, + "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')]", + "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 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')]", + "dependsOn": [ + "storageAccount" + ] + }, + "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')]" + }, + "dependsOn": [ + "storageAccount::queueServices" + ] + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), 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": "[guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', 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": [ + "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]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "16839054392438941735" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table 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." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. tables to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "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": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "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.28.1.47646", + "templateHash": "3177845984945141330" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table.", + "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." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "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')]", + "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 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')]", + "dependsOn": [ + "storageAccount" + ] + }, + "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'))]", + "dependsOn": [ + "storageAccount::tableServices" + ] + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), 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": "[guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', 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": [ + "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]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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" + ] + } + }, + "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]" + } + } + } + } + }, + "cognitiveServices": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cognitive', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('cognitiveServicesName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('cognitiveServicesKind')]" + }, + "customSubDomainName": { + "value": "[parameters('cognitiveServicesCustomSubDomainName')]" + }, + "publicNetworkAccess": { + "value": "[parameters('cognitiveServicesPublicNetworkAccess')]" + }, + "networkAcls": { + "value": "[parameters('cognitiveServicesNetworkAcls')]" + }, + "disableLocalAuth": { + "value": "[parameters('cognitiveServicesDisableLocalAuth')]" + }, + "sku": { + "value": "[parameters('cognitiveServicesSku')]" + }, + "deployments": { + "value": "[parameters('cognitiveServicesDeployments')]" + }, + "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.29.47.4906", + "templateHash": "7976342392137470716" + }, + "name": "Cognitive Services", + "description": "This module deploys a Cognitive 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 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 + }, + "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 + }, + "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. Required if a user assigned identity is used for encryption." + } + } + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "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 + }, + "deploymentsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + } + } + }, + "nullable": true + }, + "endpointsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "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." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "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." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "$ref": "#/definitions/deploymentsType", + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts 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', 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": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "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')]" + } + }, + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('0.7.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" + } + } + } + } + }, + "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'), '/'))]" + }, + "cognitiveService": { + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2023-05-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2023-05-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku')))]", + "dependsOn": [ + "cognitiveService" + ] + }, + "cognitiveService_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.CognitiveServices/accounts/{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": [ + "cognitiveService" + ] + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.CognitiveServices/accounts/{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": [ + "cognitiveService" + ] + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', 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": [ + "cognitiveService" + ] + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cognitiveService-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.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), 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.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), 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.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), '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'))]" + }, + "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.29.47.4906", + "templateHash": "13720311665093076615" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "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 + }, + "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 + } + }, + "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": { + "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.6.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('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.29.47.4906", + "templateHash": "15263454436186512874" + }, + "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-11-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-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "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": [ + "cognitiveService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services account." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The service endpoint of the cognitive services account." + }, + "value": "[reference('cognitiveService').endpoint]" + }, + "endpoints": { + "$ref": "#/definitions/endpointsType", + "metadata": { + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." + }, + "value": "[reference('cognitiveService').endpoints]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('cognitiveService', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('cognitiveService', '2023-05-01', 'full').location]" + } + } + } + } + }, + "logAnalytics": { + "condition": "[not(empty(parameters('logAnalyticsName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-loganalytics', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('logAnalyticsName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": "[parameters('dataRetention')]" + }, + "skuName": { + "value": "[parameters('logAnalyticsSkuName')]" + }, + "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.29.47.4906", + "templateHash": "14441228139596902410" + }, + "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 + }, + "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." + } + }, + "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." + } + } + } + }, + "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." + } + }, + "linkedServices": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "defaultValue": [], + "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", + "defaultValue": [], + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics 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." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "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", + "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)))))]" + } + ], + "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 (Preview)": "[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('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" + } + } + } + } + }, + "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_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_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(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": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'tables')]" + }, + "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.29.47.4906", + "templateHash": "1745671120474305926" + }, + "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]" + } + }, + "dependsOn": [ + "storageAccount", + "workspace" + ] + } + }, + "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(parameters('linkedServices'))]" + }, + "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": "[parameters('linkedServices')[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(parameters('linkedServices')[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(parameters('linkedServices')[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.29.47.4906", + "templateHash": "12032441371027552374" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service.", + "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", + "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'))]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('linkedStorageAccounts'))]" + }, + "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": "[parameters('linkedStorageAccounts')[copyIndex()].name]" + }, + "resourceId": { + "value": "[parameters('linkedStorageAccounts')[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.29.47.4906", + "templateHash": "12623216644328477682" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account.", + "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", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": [ + "[parameters('resourceId')]" + ] + } + } + ], + "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(parameters('savedSearches'))]" + }, + "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}', parameters('savedSearches')[copyIndex()].name, uniqueString(deployment().name))]" + }, + "etag": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[parameters('savedSearches')[copyIndex()].displayName]" + }, + "category": { + "value": "[parameters('savedSearches')[copyIndex()].category]" + }, + "query": { + "value": "[parameters('savedSearches')[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionParameters')]" + }, + "version": { + "value": "[tryGet(parameters('savedSearches')[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.29.47.4906", + "templateHash": "7683333179440464721" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search.", + "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", + "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": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-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')]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('dataExports'))]" + }, + "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": "[parameters('dataExports')[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5765609820817623497" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export.", + "owner": "Azure/module-maintainers" + }, + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2020-08-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(parameters('dataSources'))]" + }, + "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": "[parameters('dataSources')[copyIndex()].name]" + }, + "kind": { + "value": "[parameters('dataSources')[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'performanceCounters')]" + } + }, + "template": { + "$schema": "https://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": "13460038983765020046" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source.", + "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", + "metadata": { + "description": "Required. Name of the solution." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Required. The kind of the DataSource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "linkedResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "defaultValue": "", + "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", + "defaultValue": "", + "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", + "defaultValue": "", + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "defaultValue": "", + "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": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2020-08-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())]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('tables'))]" + }, + "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": "[parameters('tables')[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'searchResults')]" + }, + "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.29.47.4906", + "templateHash": "6905244456918791391" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table.", + "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 + } + }, + "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": { + "type": "object", + "defaultValue": {}, + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "type": "object", + "defaultValue": {}, + "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": { + "$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')]", + "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 (Preview)": "[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": "2022-10-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-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')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "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(parameters('gallerySolutions'))]" + }, + "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": "[parameters('gallerySolutions')[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "product": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'product')]" + }, + "publisher": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'publisher')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('gallerySolutions')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "18444780972506374592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution. For Microsoft published gallery solution the target solution resource name will be composed as `{name}({logAnalyticsWorkspaceName})`." + } + }, + "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." + } + }, + "product": { + "type": "string", + "defaultValue": "OMSGallery", + "metadata": { + "description": "Optional. The product of the deployed solution. For Microsoft published gallery solution it should be `OMSGallery` and the target solution resource product will be composed as `OMSGallery/{name}`. For third party solution, it can be anything. This is case sensitive." + } + }, + "publisher": { + "type": "string", + "defaultValue": "Microsoft", + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "solutionName": "[if(equals(parameters('publisher'), 'Microsoft'), format('{0}({1})', parameters('name'), parameters('logAnalyticsWorkspaceName')), parameters('name'))]", + "solutionProduct": "[if(equals(parameters('publisher'), 'Microsoft'), format('OMSGallery/{0}', parameters('name')), parameters('product'))]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[variables('solutionName')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[variables('solutionName')]", + "promotionCode": "", + "product": "[variables('solutionProduct')]", + "publisher": "[parameters('publisher')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[variables('solutionName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName'))]" + }, + "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(resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName')), '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', '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'), '')]" + } + } + } + } + }, + "applicationInsights": { + "condition": "[and(not(empty(parameters('applicationInsightsName'))), not(empty(parameters('logAnalyticsName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-insights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "name": { + "value": "[parameters('applicationInsightsName')]" + }, + "dashboardName": { + "value": "[parameters('applicationInsightsDashboardName')]" + }, + "logAnalyticsWorkspaceResourceId": "[if(not(empty(parameters('logAnalyticsName'))), createObject('value', reference('logAnalytics').outputs.resourceId.value), createObject('value', ''))]", + "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.29.47.4906", + "templateHash": "17156187352453961206" + }, + "name": "Application Insights Components", + "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "dashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "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." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the loganalytics workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "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." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-insightsdashboard.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "applicationInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appinsights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('kind')]" + }, + "applicationType": { + "value": "[parameters('applicationType')]" + }, + "workspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://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": "10653241142071426932" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance.", + "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 + }, + "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. 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", + "defaultValue": "", + "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." + } + }, + "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." + } + }, + "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." + } + }, + "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')]", + "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('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" + } + } + } + } + }, + "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')]" + } + }, + "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_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": "[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.29.47.4906", + "templateHash": "216781367921725873" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account.", + "owner": "Azure/module-maintainers" + }, + "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]" + } + } + } + } + }, + "applicationInsightsDashboard": { + "condition": "[not(empty(parameters('dashboardName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "application-insights-dashboard", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('dashboardName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "applicationInsightsName": { + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "applicationInsightsResourceId": { + "value": "[reference('applicationInsights').outputs.resourceId.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.29.47.4906", + "templateHash": "9856731218551847403" + }, + "name": "Azure Portal Dashboard", + "description": "Creates a dashboard for an Application Insights instance.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The portal dashboard name." + } + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components ID." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "dashboard": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "dashboard-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "lenses": { + "value": [ + { + "order": 0, + "parts": [ + { + "position": { + "x": 0, + "y": 0, + "colSpan": 2, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "id", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart", + "asset": { + "idInputName": "id", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "overview" + } + }, + { + "position": { + "x": 2, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "ProactiveDetection" + } + }, + { + "position": { + "x": 3, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + } + ], + "type": "Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:20:33.345Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 5, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-08T18:47:35.237Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "ConfigurationId", + "value": "78ce933e-e864-4b05-a27b-71fd55a6afad" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AppMapButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 0, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Usage", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 3, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:22:35.782Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + } + ], + "type": "Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Reliability", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 7, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:42:40.072Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "failures" + } + }, + { + "position": { + "x": 8, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Responsiveness\r\n", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 11, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:43:37.804Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "2a8ede4f-2bee-4b9c-aed9-2db0e8a01865", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "performance" + } + }, + { + "position": { + "x": 12, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Browser", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 15, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "MetricsExplorerJsonDefinitionId", + "value": "BrowserPerformanceTimelineMetrics" + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "createdTime": "2018-05-08T12:16:27.534Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "CurrentFilter", + "value": { + "eventTypes": [ + 4, + 1, + 3, + 5, + 2, + 6, + 13 + ], + "typeFacets": {}, + "isPermissive": false + } + }, + { + "name": "id", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "browser" + } + }, + { + "position": { + "x": 0, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "sessions/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Sessions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "users/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Users", + "color": "#7E58FF" + } + } + ], + "title": "Unique sessions and users", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "segmentationUsers" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Failed requests", + "color": "#EC008C" + } + } + ], + "title": "Failed requests", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "failures" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/duration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server response time", + "color": "#00BCF2" + } + } + ], + "title": "Server response time", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "performance" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/networkDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Page load network connect time", + "color": "#7E58FF" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/processingDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Client processing time", + "color": "#44F1C8" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/sendDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Send request time", + "color": "#EB9371" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/receiveDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Receiving response time", + "color": "#0672F1" + } + } + ], + "title": "Average page load time breakdown", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/availabilityPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability", + "color": "#47BDF5" + } + } + ], + "title": "Average availability", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "availability" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/server", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server exceptions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "dependencies/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Dependency failures", + "color": "#7E58FF" + } + } + ], + "title": "Server exceptions and Dependency failures", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processorCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Processor time", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process CPU", + "color": "#7E58FF" + } + } + ], + "title": "Average processor and process CPU utilization", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/browser", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Browser exceptions", + "color": "#47BDF5" + } + } + ], + "title": "Browser exceptions", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/count", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability test results count", + "color": "#47BDF5" + } + } + ], + "title": "Availability test results count", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processIOBytesPerSecond", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process IO rate", + "color": "#47BDF5" + } + } + ], + "title": "Average process I/O rate", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/memoryAvailableBytes", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Available memory", + "color": "#47BDF5" + } + } + ], + "title": "Average available memory", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "12676032921679464791" + }, + "name": "Portal Dashboards", + "description": "This module deploys a Portal Dashboard.", + "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 + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the dashboard 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." + } + }, + "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." + } + }, + "lenses": { + "type": "array", + "items": { + "type": "object" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The dashboard lenses." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The dashboard metadata." + } + } + }, + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.portal-dashboard.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "dashboard": { + "type": "Microsoft.Portal/dashboards", + "apiVersion": "2020-09-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "lenses": "[parameters('lenses')]", + "metadata": "[parameters('metadata')]" + } + }, + "dashboard_roleAssignments": { + "copy": { + "name": "dashboard_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Portal/dashboards/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Portal/dashboards', 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": [ + "dashboard" + ] + }, + "dashboard_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.Portal/dashboards/{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": [ + "dashboard" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[resourceId('Microsoft.Portal/dashboards', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dashboard was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the dashboard." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the dashboard was deployed into." + }, + "value": "[reference('dashboard', '2020-09-01-preview', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[reference('dashboard').outputs.resourceId.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[reference('dashboard').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "applicationInsights" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights components were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardName.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardResourceId.value, '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[reference('applicationInsights').outputs.connectionString.value]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[reference('applicationInsights').outputs.instrumentationKey.value]" + } + } + } + }, + "dependsOn": [ + "logAnalytics" + ] + }, + "containerRegistry": { + "condition": "[not(empty(parameters('containerRegistryName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('containerRegistryName')]" + }, + "acrSku": { + "value": "[parameters('registryAcrSku')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publicNetworkAccess": { + "value": "[parameters('registryPublicNetworkAccess')]" + }, + "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.29.47.4906", + "templateHash": "8799580877381308457" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR).", + "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 + }, + "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", + "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 + }, + "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 + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "scopeMapsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "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." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registr is enabled or not. Default is enabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "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 networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "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." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "$ref": "#/definitions/scopeMapsType", + "metadata": { + "description": "Optional. Scope maps setting." + } + } + }, + "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": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "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')]" + } + }, + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{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" + } + } + } + } + }, + "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'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(not(empty(parameters('networkRuleSetIpRules'))), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', parameters('networkRuleSetIpRules')), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "registry_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.ContainerRegistry/registries/{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": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerRegistry/registries/{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": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', 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": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "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.29.47.4906", + "templateHash": "9144531012597082524" + }, + "name": "Container Registries scopeMaps", + "description": "This module deploys an Azure Container Registry (ACR) scopeMap.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), 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.29.47.4906", + "templateHash": "8531695368487734118" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "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." + } + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + } + }, + "template": { + "$schema": "https://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": "12196074162662855376" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set.", + "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." + } + } + } + }, + "authCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Required. The managed identity definition for this resource." + } + }, + "authCredentials": { + "$ref": "#/definitions/authCredentialsType", + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "variables": { + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]" + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2023-11-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[variables('identity')]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('credentialSet', '2023-11-01-preview', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name'), replace(replace(coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository, '/', '-'), '.', '-'))]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "4294329625336671928" + }, + "name": "Container Registries Cache", + "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be dereived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action'), createArray('chart_delete', 'chart_push', 'delete', 'push', 'quarantine'))]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), 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.29.47.4906", + "templateHash": "14912363209364245195" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "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." + } + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), 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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), 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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), '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'))]" + }, + "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": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2019-05-01').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('registry', '2023-06-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2023-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.systemAssignedMIPrincipalId.value]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.resourceId.value]" + } + } + } + } + } + }, + "searchService": { + "condition": "[not(empty(parameters('searchServiceName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchservice', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('searchServiceName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "authOptions": { + "value": "[parameters('authOptions')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "cmkEnforcement": { + "value": "[parameters('cmkEnforcement')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "networkRuleSet": { + "value": "[parameters('networkRuleSet')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "publicNetworkAccess": { + "value": "[parameters('searchServicePublicNetworkAccess')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "sku": { + "value": "[parameters('searchServiceSku')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "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.29.47.4906", + "templateHash": "14924554723661229870" + }, + "name": "Search Services", + "description": "This module deploys a Search Service.", + "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. Required if a user assigned identity is used for encryption." + } + } + }, + "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", + "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": "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 + }, + "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 Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." + } + }, + "authOptions": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default", + "highDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "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." + } + }, + "networkRuleSet": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to help categorize the resource in the Azure portal." + } + } + }, + "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', '')), '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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "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.search-searchservice.{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" + } + } + } + } + }, + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2024-03-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "authOptions": "[if(not(empty(parameters('authOptions'))), parameters('authOptions'), null())]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]" + } + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{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": [ + "searchService" + ] + }, + "searchService_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.Search/searchServices/{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": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', 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": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchService-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.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), 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.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), 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.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), '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": [ + "searchService" + ] + }, + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchService-SharedPrivateLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } + }, + "template": { + "$schema": "https://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": "2330033720810948871" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2023-11-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('searchService', '2024-03-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2024-03-01-preview', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the module was deployed to." + }, + "value": "[resourceGroup().name]" + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[reference('keyVault').outputs.resourceId.value]" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[reference('keyVault').outputs.name.value]" + }, + "keyVaultEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the key vault." + }, + "value": "[reference('keyVault').outputs.uri.value]" + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the storage account." + }, + "value": "[reference('storageAccount').outputs.resourceId.value]" + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "The name of the storage account." + }, + "value": "[reference('storageAccount').outputs.name.value]" + }, + "containerRegistryResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.resourceId.value, '')]" + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.name.value, '')]" + }, + "containerRegistryEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.loginServer.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsResourceId.value, '')]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsName.value, '')]" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the loganalytics workspace." + }, + "value": "[if(not(empty(parameters('logAnalyticsName'))), reference('logAnalytics').outputs.resourceId.value, '')]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the loganalytics workspace." + }, + "value": "[if(not(empty(parameters('logAnalyticsName'))), reference('logAnalytics').outputs.name.value, '')]" + }, + "cognitiveServicesResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.resourceId.value]" + }, + "cognitiveServicesName": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.name.value]" + }, + "cognitiveServicesEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.endpoint.value]" + }, + "searchServiceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.resourceId.value, '')]" + }, + "searchServiceName": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.name.value, '')]" + }, + "searchServiceEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), format('https://{0}.search.windows.net/', reference('searchService').outputs.name.value), '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsConnectionString.value, '')]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsInstrumentationKey.value, '')]" + }, + "systemAssignedMiPrincipalId": { + "type": "string", + "metadata": { + "description": "The system assigned mi principal Id key of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.systemAssignedMIPrincipalId.value, '')]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/ml-hub-dependencies/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/ml-hub-dependencies/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..478ac9d83c --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/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}-azd-ml-hub-dependencies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'hubdmin' + +@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: { + cognitiveServicesName: '${namePrefix}cog07${serviceShort}' + keyVaultName: '${namePrefix}key07${serviceShort}' + storageAccountName: '${namePrefix}st07${serviceShort}' + } + } +] diff --git a/avm/ptn/azd/ml-hub-dependencies/tests/e2e/max/main.test.bicep b/avm/ptn/azd/ml-hub-dependencies/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..19b3dd9ecd --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/tests/e2e/max/main.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module using large parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-ml-hub-dependencies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'mhdpmax' + +@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: { + cognitiveServicesName: '${namePrefix}cs08${serviceShort}' + keyVaultName: '${namePrefix}kv08${serviceShort}' + storageAccountName: '${namePrefix}sa08${serviceShort}' + applicationInsightsDashboardName: '${namePrefix}aid08${serviceShort}' + applicationInsightsName: '${namePrefix}ai08${serviceShort}' + logAnalyticsName: '${namePrefix}log08${serviceShort}' + containerRegistryName: '${namePrefix}cr08${serviceShort}' + searchServiceName: '${namePrefix}sea08${serviceShort}' + } + } +] diff --git a/avm/ptn/azd/ml-hub-dependencies/version.json b/avm/ptn/azd/ml-hub-dependencies/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From ac577d4faf81ceec81d97eedd6516f4f4af2e436 Mon Sep 17 00:00:00 2001 From: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:43:41 +0100 Subject: [PATCH 54/93] feat: Update API Version for Compute/SSH-key (#3453) ## Description Closes #3095 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.compute.ssh-public-key](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml/badge.svg?branch=ssh-key-update&event=workflow_dispatch)](https://github.com/ChrisSidebotham/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/compute/ssh-public-key/README.md | 2 +- avm/res/compute/ssh-public-key/main.bicep | 2 +- avm/res/compute/ssh-public-key/main.json | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/avm/res/compute/ssh-public-key/README.md b/avm/res/compute/ssh-public-key/README.md index 8b54ba0786..0edc87a245 100644 --- a/avm/res/compute/ssh-public-key/README.md +++ b/avm/res/compute/ssh-public-key/README.md @@ -18,7 +18,7 @@ This module deploys a Public SSH Key. | :-- | :-- | | `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` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-01/sshPublicKeys) | +| `Microsoft.Compute/sshPublicKeys` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-01/sshPublicKeys) | ## Usage examples diff --git a/avm/res/compute/ssh-public-key/main.bicep b/avm/res/compute/ssh-public-key/main.bicep index 69ab8ddac2..0292a5ffe2 100644 --- a/avm/res/compute/ssh-public-key/main.bicep +++ b/avm/res/compute/ssh-public-key/main.bicep @@ -70,7 +70,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource sshPublicKey 'Microsoft.Compute/sshPublicKeys@2023-07-01' = { +resource sshPublicKey 'Microsoft.Compute/sshPublicKeys@2024-03-01' = { name: name location: location tags: tags diff --git a/avm/res/compute/ssh-public-key/main.json b/avm/res/compute/ssh-public-key/main.json index a24878491e..6bb1479682 100644 --- a/avm/res/compute/ssh-public-key/main.json +++ b/avm/res/compute/ssh-public-key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8431280172894888036" + "version": "0.30.23.60470", + "templateHash": "5428269336337327866" }, "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.", @@ -199,7 +199,7 @@ }, "sshPublicKey": { "type": "Microsoft.Compute/sshPublicKeys", - "apiVersion": "2023-07-01", + "apiVersion": "2024-03-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -271,7 +271,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('sshPublicKey', '2023-07-01', 'full').location]" + "value": "[reference('sshPublicKey', '2024-03-01', 'full').location]" } } } \ No newline at end of file From d0cbe011179695223d49c5aec71849a758c9212a Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 10 Oct 2024 17:12:25 +0200 Subject: [PATCH 55/93] fix: Container-App-Stack - Trigger publish (#3497) ## Description - Just a small change to ensure the module is published as a previous merge did not do the trick - Also added missing passthru of `enableTelemetry` parameter to this and the insights-dashboard module --- avm/ptn/azd/container-apps-stack/README.md | 4 ++-- avm/ptn/azd/container-apps-stack/main.bicep | 4 +++- avm/ptn/azd/container-apps-stack/main.json | 6 ++--- avm/ptn/azd/insights-dashboard/main.bicep | 6 ++++- avm/ptn/azd/insights-dashboard/main.json | 24 +++++++++++++++---- .../applicationinsights-dashboard.bicep | 4 ++++ 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/avm/ptn/azd/container-apps-stack/README.md b/avm/ptn/azd/container-apps-stack/README.md index 1702795bd4..a01a8ffb71 100644 --- a/avm/ptn/azd/container-apps-stack/README.md +++ b/avm/ptn/azd/container-apps-stack/README.md @@ -197,7 +197,7 @@ param zoneRedundant = true | :-- | :-- | :-- | | [`dockerBridgeCidr`](#parameter-dockerbridgecidr) | string | CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`infrastructureSubnetResourceId`](#parameter-infrastructuresubnetresourceid) | string | Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if "internal" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant. | -| [`internal`](#parameter-internal) | bool | Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant. | +| [`internal`](#parameter-internal) | bool | Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant. | | [`platformReservedCidr`](#parameter-platformreservedcidr) | string | IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`platformReservedDnsIP`](#parameter-platformreserveddnsip) | string | An IP address from the IP range defined by "platformReservedCidr" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`workloadProfiles`](#parameter-workloadprofiles) | array | Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant. | @@ -256,7 +256,7 @@ Resource ID of a subnet for infrastructure components. This is used to deploy th ### Parameter: `internal` -Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant. +Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant. - Required: No - Type: bool diff --git a/avm/ptn/azd/container-apps-stack/main.bicep b/avm/ptn/azd/container-apps-stack/main.bicep index 1319e17f2d..db11a5ed46 100644 --- a/avm/ptn/azd/container-apps-stack/main.bicep +++ b/avm/ptn/azd/container-apps-stack/main.bicep @@ -53,7 +53,7 @@ param dockerBridgeCidr string = '' @description('Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if "internal" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant.') param infrastructureSubnetResourceId string = '' -@description('Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant.') +@description('Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if \'zoneRedundant\' is set to true to make the resource WAF compliant.') param internal bool = false @description('Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant.') @@ -104,6 +104,7 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.7.0 dockerBridgeCidr: dockerBridgeCidr platformReservedCidr: platformReservedCidr platformReservedDnsIP: platformReservedDnsIP + enableTelemetry: enableTelemetry } } @@ -118,6 +119,7 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = acrAdminUserEnabled: acrAdminUserEnabled tags: tags acrSku: acrSku + enableTelemetry: enableTelemetry } } diff --git a/avm/ptn/azd/container-apps-stack/main.json b/avm/ptn/azd/container-apps-stack/main.json index f58de2af0b..49ae1b6b15 100644 --- a/avm/ptn/azd/container-apps-stack/main.json +++ b/avm/ptn/azd/container-apps-stack/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "332940780345983600" + "version": "0.30.23.60470", + "templateHash": "2135275469617068705" }, "name": "avm/ptn/azd/container-apps-stack", "description": "Creates an Azure Container Registry and an Azure Container Apps environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", @@ -117,7 +117,7 @@ "type": "bool", "defaultValue": false, "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetId\" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant." } }, "platformReservedCidr": { diff --git a/avm/ptn/azd/insights-dashboard/main.bicep b/avm/ptn/azd/insights-dashboard/main.bicep index 911a2471a7..929b1fd5be 100644 --- a/avm/ptn/azd/insights-dashboard/main.bicep +++ b/avm/ptn/azd/insights-dashboard/main.bicep @@ -72,6 +72,7 @@ module applicationInsights 'br/public:avm/res/insights/component:0.4.1' = { kind: kind applicationType: applicationType workspaceResourceId: logAnalyticsWorkspaceResourceId + enableTelemetry: enableTelemetry } } @@ -82,6 +83,7 @@ module applicationInsightsDashboard 'modules/applicationinsights-dashboard.bicep location: location applicationInsightsName: applicationInsights.outputs.name applicationInsightsResourceId: applicationInsights.outputs.resourceId + enableTelemetry: enableTelemetry } } @@ -102,7 +104,9 @@ output dashboardName string = !empty(dashboardName) ? applicationInsightsDashboa output applicationInsightsResourceId string = applicationInsights.outputs.resourceId @description('The resource ID of the dashboard.') -output dashboardResourceId string = !empty(dashboardName) ? applicationInsightsDashboard.outputs.dashboardResourceId : '' +output dashboardResourceId string = !empty(dashboardName) + ? applicationInsightsDashboard.outputs.dashboardResourceId + : '' @description('The connection string of the application insights.') output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString diff --git a/avm/ptn/azd/insights-dashboard/main.json b/avm/ptn/azd/insights-dashboard/main.json index ed2893f7d0..a082c79e6f 100644 --- a/avm/ptn/azd/insights-dashboard/main.json +++ b/avm/ptn/azd/insights-dashboard/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16185324363882257699" + "version": "0.30.23.60470", + "templateHash": "15067669928476640283" }, "name": "Application Insights Components", "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -121,6 +121,9 @@ }, "workspaceResourceId": { "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -758,6 +761,9 @@ }, "applicationInsightsResourceId": { "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -767,8 +773,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "12382758204242351890" + "version": "0.30.23.60470", + "templateHash": "10844955132300564569" }, "name": "Azure Portal Dashboard", "description": "Creates a dashboard for an Application Insights instance.", @@ -800,6 +806,13 @@ "description": "Optional. Location for all Resources." } }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, "tags": { "type": "object", "nullable": true, @@ -829,6 +842,9 @@ "tags": { "value": "[parameters('tags')]" }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, "lenses": { "value": [ { diff --git a/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep b/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep index 4a08622f49..f358fa0a74 100644 --- a/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep +++ b/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep @@ -14,6 +14,9 @@ param applicationInsightsResourceId 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. Tags of the resource.') @metadata({ example: ''' @@ -35,6 +38,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:0.1.0' = { name: name location: location tags: tags + enableTelemetry: enableTelemetry lenses: [ { order: 0 From 2363f4dca32fead868b926ba7ec075f0e53e15c1 Mon Sep 17 00:00:00 2001 From: Zach Trocinski Date: Thu, 10 Oct 2024 15:23:33 -0500 Subject: [PATCH 56/93] Initial test files --- .../authorization/policy-exemption/README.md | 1005 ++++++++++++++++- .../authorization/policy-exemption/main.bicep | 14 +- .../modules/management-group.bicep | 8 +- .../modules/resource-group.bicep | 8 +- .../modules/subscription.bicep | 8 +- .../tests/e2e/defaults/main.test.bicep | 48 - .../tests/e2e/mg.defaults/main.test.bicep | 54 + .../tests/e2e/mg.max/main.test.bicep | 54 + .../tests/e2e/rg.defaults/main.test.bicep | 54 + .../tests/e2e/rg.max/main.test.bicep | 54 + .../tests/e2e/sub.defaults/main.test.bicep | 54 + .../tests/e2e/sub.max/main.test.bicep | 54 + .../tests/e2e/waf-aligned/main.test.bicep | 48 - 13 files changed, 1338 insertions(+), 125 deletions(-) delete mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep create mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep delete mode 100644 avm/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep diff --git a/avm/ptn/authorization/policy-exemption/README.md b/avm/ptn/authorization/policy-exemption/README.md index 30387c930b..a5230818c4 100644 --- a/avm/ptn/authorization/policy-exemption/README.md +++ b/avm/ptn/authorization/policy-exemption/README.md @@ -24,10 +24,14 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/authorization/policy-exemption:`. -- [Defaults](#example-1-defaults) -- [Waf-Aligned](#example-2-waf-aligned) +- [Mg.Defaults](#example-1-mgdefaults) +- [Mg.Max](#example-2-mgmax) +- [Rg.Defaults](#example-3-rgdefaults) +- [Rg.Max](#example-4-rgmax) +- [Sub.Defaults](#example-5-subdefaults) +- [Sub.Max](#example-6-submax) -### Example 1: _Defaults_ +### Example 1: _Mg.Defaults_

    @@ -38,8 +42,146 @@ module policyExemption 'br/public:avm/ptn/authorization/policy-exemption: +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "assignmentScopeValidation": { + "value": "Default" + }, + "exemptionCategory": { + "value": "Mitigated" + }, + "expiresOn": { + "value": "2023-10-05T14:48:00Z" + }, + "name": { + "value": "apemgmin001" + }, + "policyAssignmentId": { + "value": "test" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-exemption:' + +// Required parameters +param assignmentScopeValidation = 'Default' +param exemptionCategory = 'Mitigated' +param expiresOn = '2023-10-05T14:48:00Z' +param name = 'apemgmin001' +param policyAssignmentId = 'test' +``` + +
    +

    + +### Example 2: _Mg.Max_ + +

    + +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + // Non-required parameters + name: 'apamgmax001' + 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: [ + '/subscriptions//resourceGroups/validation-rg' + ] + overrides: [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } + ] + parameters: { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } + } + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + 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' + ] } } ``` @@ -58,10 +200,101 @@ module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:" + }, + "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": [ + "/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 + } + } + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611" + }, + "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" + ] } } } @@ -78,14 +311,79 @@ module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' // Required parameters -param name = 'apedef001' +// Non-required parameters +param name = 'apamgmax001' +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 = [ + '/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 policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +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 2: _Waf-Aligned_ +### Example 3: _Rg.Defaults_

    @@ -96,8 +394,15 @@ module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' + metadata: { + assignedBy: 'Bicep' + } + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + resourceGroupName: '' + subscriptionId: '' } } ``` @@ -116,10 +421,25 @@ module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:" + }, + "metadata": { + "value": { + "assignedBy": "Bicep" + } + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d" + }, + "resourceGroupName": { + "value": "" + }, + "subscriptionId": { + "value": "" } } } @@ -136,8 +456,673 @@ module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' // Required parameters -param name = 'apewaf001' +// Non-required parameters +param name = 'apargmin001' param location = '' +param metadata = { + assignedBy: 'Bicep' +} +param policyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
    +

    + +### Example 4: _Rg.Max_ + +

    + +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + // Non-required parameters + name: 'apargmax001' + 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 + } + } + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + 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" + }, + // 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 + } + } + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611" + }, + "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-exemption:' + +// Required parameters +// Non-required parameters +param name = 'apargmax001' +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 policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +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: _Sub.Defaults_ + +

    + +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + name: 'apasubmin001' + location: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' + } + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + 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" + }, + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security", + "version": "1.0" + } + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
    +

    + +

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

    + +### Example 6: _Sub.Max_ + +

    + +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + // Non-required parameters + name: 'apasubmax001' + 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 + } + } + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + 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" + }, + // 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 + } + } + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611" + }, + "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-exemption:' + +// Required parameters +// Non-required parameters +param name = 'apasubmax001' +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 policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +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 = '' ```
    diff --git a/avm/ptn/authorization/policy-exemption/main.bicep b/avm/ptn/authorization/policy-exemption/main.bicep index a62bf4a7dc..b1b2bf747b 100644 --- a/avm/ptn/authorization/policy-exemption/main.bicep +++ b/avm/ptn/authorization/policy-exemption/main.bicep @@ -13,7 +13,7 @@ param name string 'DoNotValidate' 'Default' ]) -param assignmentScopeValidation string +param assignmentScopeValidation string = 'Default' @sys.description('Optional. This message will be part of response in case of policy violation.') param description string = '' @@ -30,9 +30,9 @@ param displayName string = '' 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(32) -@minLength(32) -param expiresOn string +@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 = {} @@ -92,7 +92,7 @@ module policyExemption_mg 'modules/management-group.bicep' = if (empty(subscript displayName: !empty(displayName) ? displayName : null assignmentScopeValidation: assignmentScopeValidation exemptionCategory: exemptionCategory - expiresOn: !empty(expiresOn) ? expiresOn : '' + expiresOn: expiresOn metadata: !empty(metadata) ? metadata : null policyAssignmentId: policyAssignmentId policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null @@ -109,7 +109,7 @@ module policyExemption_sub 'modules/subscription.bicep' = if (!empty(subscriptio displayName: !empty(displayName) ? displayName : null assignmentScopeValidation: assignmentScopeValidation exemptionCategory: exemptionCategory - expiresOn: !empty(expiresOn) ? expiresOn : '' + expiresOn: expiresOn metadata: !empty(metadata) ? metadata : null policyAssignmentId: policyAssignmentId policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null @@ -126,7 +126,7 @@ module policyExemption_rg 'modules/resource-group.bicep' = if (!empty(resourceGr displayName: !empty(displayName) ? displayName : null assignmentScopeValidation: assignmentScopeValidation exemptionCategory: exemptionCategory - expiresOn: !empty(expiresOn) ? expiresOn : '' + expiresOn: expiresOn metadata: !empty(metadata) ? metadata : null policyAssignmentId: policyAssignmentId policyDefinitionReferenceIds: !empty(policyDefinitionReferenceIds) ? policyDefinitionReferenceIds : null diff --git a/avm/ptn/authorization/policy-exemption/modules/management-group.bicep b/avm/ptn/authorization/policy-exemption/modules/management-group.bicep index eb5d13b81b..acb1bc7544 100644 --- a/avm/ptn/authorization/policy-exemption/modules/management-group.bicep +++ b/avm/ptn/authorization/policy-exemption/modules/management-group.bicep @@ -13,7 +13,7 @@ param name string 'DoNotValidate' 'Default' ]) -param assignmentScopeValidation string +param assignmentScopeValidation string = 'Default' @sys.description('Optional. This message will be part of response in case of policy violation.') param description string = '' @@ -30,9 +30,9 @@ param displayName string = '' 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(32) -@minLength(32) -param expiresOn string +@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 = {} diff --git a/avm/ptn/authorization/policy-exemption/modules/resource-group.bicep b/avm/ptn/authorization/policy-exemption/modules/resource-group.bicep index 43b720e473..e5878900e0 100644 --- a/avm/ptn/authorization/policy-exemption/modules/resource-group.bicep +++ b/avm/ptn/authorization/policy-exemption/modules/resource-group.bicep @@ -13,7 +13,7 @@ param name string 'DoNotValidate' 'Default' ]) -param assignmentScopeValidation string +param assignmentScopeValidation string = 'Default' @sys.description('Optional. This message will be part of response in case of policy violation.') param description string = '' @@ -30,9 +30,9 @@ param displayName string = '' 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(32) -@minLength(32) -param expiresOn string +@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 = {} diff --git a/avm/ptn/authorization/policy-exemption/modules/subscription.bicep b/avm/ptn/authorization/policy-exemption/modules/subscription.bicep index 7e74aa426d..01bd3ea9b1 100644 --- a/avm/ptn/authorization/policy-exemption/modules/subscription.bicep +++ b/avm/ptn/authorization/policy-exemption/modules/subscription.bicep @@ -13,7 +13,7 @@ param name string 'DoNotValidate' 'Default' ]) -param assignmentScopeValidation string +param assignmentScopeValidation string = 'Default' @sys.description('Optional. This message will be part of response in case of policy violation.') param description string = '' @@ -30,9 +30,9 @@ param displayName string = '' 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(32) -@minLength(32) -param expiresOn string +@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 = {} diff --git a/avm/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep deleted file mode 100644 index 56af9ab567..0000000000 --- a/avm/ptn/authorization/policy-exemption/tests/e2e/defaults/main.test.bicep +++ /dev/null @@ -1,48 +0,0 @@ -targetScope = 'subscription' - -// ========== // -// 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}---${serviceShort}-rg' - -@description('Optional. The location to deploy resources to.') -param resourceLocation string = 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 = 'apedef' - -@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 - name: '${namePrefix}${serviceShort}001' - location: resourceLocation - } - } -] diff --git a/avm/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep new file mode 100644 index 0000000000..1e178ac60a --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep @@ -0,0 +1,54 @@ +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('Required. The name of the policy assignment to deploy.') +param policyAssignmentName string = 'audit-vm-managed-disks' + +@description('Required. The policy definition ID to assign the policy to.') +param policyDefinitionID string = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + +@description('Optional. The display name of the policy.') +param policyDisplayName string = 'Audit VM managed disks' + +@description('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 policyAssignment 'Microsoft.Authorization/policyAssignments@2023-04-01' = { + name: policyAssignmentName + scope: managementGroup() + properties: { + policyDefinitionId: policyDefinitionID + description: 'Policy assignment to resource group scope created with Bicep file' + displayName: policyDisplayName + 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/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep new file mode 100644 index 0000000000..fe84f51e4a --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep @@ -0,0 +1,54 @@ +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. The name of the management group to deploy for testing purposes.') +param policyAssignmentName string = 'audit-vm-managed-disks' + +@description('Optional. The policy definition ID to assign the policy to.') +param policyDefinitionID string = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + +@description('Optional. The display name of the policy.') +param policyDisplayName string = 'Audit VM managed disks' + +@description('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 policyAssignment 'Microsoft.Authorization/policyAssignments@2023-04-01' = { + name: policyAssignmentName + scope: managementGroup() + properties: { + policyDefinitionId: policyDefinitionID + description: 'Policy assignment to resource group scope created with Bicep file' + displayName: policyDisplayName + 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/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep new file mode 100644 index 0000000000..310bd7b10e --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep @@ -0,0 +1,54 @@ +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 management group to deploy for testing purposes.') +param policyAssignmentName string = 'audit-vm-managed-disks' + +@description('Optional. The policy definition ID to assign the policy to.') +param policyDefinitionID string = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + +@description('Optional. The display name of the policy.') +param policyDisplayName string = 'Audit VM managed disks' + +@description('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 location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2023-04-01' = { + name: policyAssignmentName + scope: managementGroup() + properties: { + policyDefinitionId: policyDefinitionID + description: 'Policy assignment to resource group scope created with Bicep file' + displayName: policyDisplayName + 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/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep new file mode 100644 index 0000000000..c7131004a2 --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep @@ -0,0 +1,54 @@ +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 management group to deploy for testing purposes.') +param policyAssignmentName string = 'audit-vm-managed-disks' + +@description('Optional. The policy definition ID to assign the policy to.') +param policyDefinitionID string = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + +@description('Optional. The display name of the policy.') +param policyDisplayName string = 'Audit VM managed disks' + +@description('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 location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2023-04-01' = { + name: policyAssignmentName + scope: managementGroup() + properties: { + policyDefinitionId: policyDefinitionID + description: 'Policy assignment to resource group scope created with Bicep file' + displayName: policyDisplayName + 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/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep new file mode 100644 index 0000000000..b82d665094 --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep @@ -0,0 +1,54 @@ +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 management group to deploy for testing purposes.') +param policyAssignmentName string = 'audit-vm-managed-disks' + +@description('Optional. The policy definition ID to assign the policy to.') +param policyDefinitionID string = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + +@description('Optional. The display name of the policy.') +param policyDisplayName string = 'Audit VM managed disks' + +@description('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 location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2023-04-01' = { + name: policyAssignmentName + scope: managementGroup() + properties: { + policyDefinitionId: policyDefinitionID + description: 'Policy assignment to resource group scope created with Bicep file' + displayName: policyDisplayName + 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/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep new file mode 100644 index 0000000000..57581c355a --- /dev/null +++ b/avm/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep @@ -0,0 +1,54 @@ +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 management group to deploy for testing purposes.') +param policyAssignmentName string = 'audit-vm-managed-disks' + +@description('Optional. The policy definition ID to assign the policy to.') +param policyDefinitionID string = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + +@description('Optional. The display name of the policy.') +param policyDisplayName string = 'Audit VM managed disks' + +@description('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 location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2023-04-01' = { + name: policyAssignmentName + scope: managementGroup() + properties: { + policyDefinitionId: policyDefinitionID + description: 'Policy assignment to resource group scope created with Bicep file' + displayName: policyDisplayName + 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/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep b/avm/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep deleted file mode 100644 index 295de7aabe..0000000000 --- a/avm/ptn/authorization/policy-exemption/tests/e2e/waf-aligned/main.test.bicep +++ /dev/null @@ -1,48 +0,0 @@ -targetScope = 'subscription' - -// ========== // -// 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}---${serviceShort}-rg' - -@description('Optional. The location to deploy resources to.') -param resourceLocation string = 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 = 'apewaf' - -@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 - name: '${namePrefix}${serviceShort}001' - location: resourceLocation - } - } -] From 1d897ee7085c21feeaa656baee7ac21cca96d29f Mon Sep 17 00:00:00 2001 From: Javier Cevallos Date: Thu, 10 Oct 2024 15:34:44 -0700 Subject: [PATCH 57/93] fix: secure variable migration token (#3394) ## Description Closes #3172 fix: add secure validation to migrationToken parameter Implement input validation for the migrationToken parameter in the Bicep template to ensure only authorized tokens are accepted. This prevents potential misuse of the parameter and enhances the security of the deployment process. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/jceval/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=fix%2Fsecure_variable_migration_token)](https://github.com/jceval/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/cognitive-services/account/main.bicep | 1 + avm/res/cognitive-services/account/main.json | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index eb12753477..d7c788c144 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -102,6 +102,7 @@ param customerManagedKey customerManagedKeyType @description('Optional. The flag to enable dynamic throttling.') param dynamicThrottlingEnabled bool = false +@secure() @description('Optional. Resource migration token.') param migrationToken string? diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 27a5d3ba80..7f45a5e8dc 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "259342811715055071" + "version": "0.30.23.60470", + "templateHash": "325704537018634474" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -795,7 +795,7 @@ } }, "migrationToken": { - "type": "string", + "type": "securestring", "nullable": true, "metadata": { "description": "Optional. Resource migration token." @@ -1784,8 +1784,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "986606208324987345" + "version": "0.30.23.60470", + "templateHash": "12263717469683062316" } }, "definitions": { From 0238a6722c029f35d6c8f2996d2f6f43316d1166 Mon Sep 17 00:00:00 2001 From: hundredacres Date: Thu, 10 Oct 2024 23:57:40 -0700 Subject: [PATCH 58/93] fix: Add support for forced tunneling (#3373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Adds param to enable forcedTunneling, which adds a managementIPAddress. Fixes #3368 Closes #3368 ## Pipeline Reference | Pipeline | | -------- | [![avm.res.network.azure-firewall](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=fix%2Fissues%2F3368)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [X] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/res/network/azure-firewall/README.md | 128 +++++++++++++++++- avm/res/network/azure-firewall/main.bicep | 11 +- avm/res/network/azure-firewall/main.json | 29 ++-- .../tests/e2e/tunneling/dependencies.bicep | 59 ++++++++ .../tests/e2e/tunneling/main.test.bicep | 70 ++++++++++ 5 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep create mode 100644 avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index 5d8d346c88..282958f330 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -18,7 +18,7 @@ This module deploys an Azure Firewall. | `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` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/azureFirewalls) | +| `Microsoft.Network/azureFirewalls` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/azureFirewalls) | | `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | ## Usage examples @@ -37,7 +37,8 @@ The following section provides usage examples for the module, which were used to - [Hub-min](#example-6-hub-min) - [Using large parameter set](#example-7-using-large-parameter-set) - [Public-IP-Prefix](#example-8-public-ip-prefix) -- [WAF-aligned](#example-9-waf-aligned) +- [Forced tunneling](#example-9-forced-tunneling) +- [WAF-aligned](#example-10-waf-aligned) ### Example 1: _Add-PIP_ @@ -1295,7 +1296,117 @@ param zones = []

    -### Example 9: _WAF-aligned_ +### 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. @@ -1718,6 +1829,7 @@ param zones = [ | [`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. | @@ -2111,6 +2223,14 @@ Resource ID of the diagnostic log analytics workspace. For security reasons, it - Required: No - Type: string +### Parameter: `enableForcedTunneling` + +Enable/Disable forced tunneling. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `enableTelemetry` Enable/Disable usage telemetry for module. @@ -2713,7 +2833,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/public-ip-address:0.5.1` | Remote reference | +| `br/public:avm/res/network/public-ip-address:0.6.0` | Remote reference | ## Data Collection diff --git a/avm/res/network/azure-firewall/main.bicep b/avm/res/network/azure-firewall/main.bicep index dc6a94ce87..39fd9b8fc0 100644 --- a/avm/res/network/azure-firewall/main.bicep +++ b/avm/res/network/azure-firewall/main.bicep @@ -66,6 +66,9 @@ param zones array = [ 3 ] +@description('Optional. Enable/Disable forced tunneling.') +param enableForcedTunneling bool = false + @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType @@ -85,7 +88,7 @@ param tags object? param enableTelemetry bool = true var azureSkuName = empty(virtualNetworkResourceId) ? 'AZFW_Hub' : 'AZFW_VNet' -var requiresManagementIp = azureSkuTier == 'Basic' ? true : false +var requiresManagementIp = (azureSkuTier == 'Basic' || enableForcedTunneling) ? true : false var isCreateDefaultManagementIP = empty(managementIPResourceID) && requiresManagementIp // ---------------------------------------------------------------------------- @@ -193,7 +196,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { +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 @@ -224,7 +227,7 @@ module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if } // 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.5.1' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { +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') @@ -257,7 +260,7 @@ module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = } } -resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = { +resource azureFirewall 'Microsoft.Network/azureFirewalls@2024-01-01' = { name: name location: location zones: length(zones) == 0 ? null : zones diff --git a/avm/res/network/azure-firewall/main.json b/avm/res/network/azure-firewall/main.json index 75a9bfba6a..43d731614e 100644 --- a/avm/res/network/azure-firewall/main.json +++ b/avm/res/network/azure-firewall/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1087268001408720205" + "version": "0.30.3.12046", + "templateHash": "7724811109136350489" }, "name": "Azure Firewalls", "description": "This module deploys an Azure Firewall.", @@ -791,6 +791,13 @@ "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": { @@ -850,7 +857,7 @@ } ], "azureSkuName": "[if(empty(parameters('virtualNetworkResourceId')), 'AZFW_Hub', 'AZFW_VNet')]", - "requiresManagementIp": "[if(equals(parameters('azureSkuTier'), 'Basic'), true(), false())]", + "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')]", @@ -883,7 +890,7 @@ }, "azureFirewall": { "type": "Microsoft.Network/azureFirewalls", - "apiVersion": "2023-04-01", + "apiVersion": "2024-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "zones": "[if(equals(length(parameters('zones')), 0), null(), parameters('zones'))]", @@ -1017,7 +1024,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14450344965065009842" + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -1466,7 +1473,7 @@ "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')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -1474,7 +1481,7 @@ "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))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1670,7 +1677,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14450344965065009842" + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -2119,7 +2126,7 @@ "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')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -2127,7 +2134,7 @@ "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))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2345,7 +2352,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('azureFirewall', '2023-04-01', 'full').location]" + "value": "[reference('azureFirewall', '2024-01-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep b/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep new file mode 100644 index 0000000000..8497ceafc0 --- /dev/null +++ b/avm/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/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep new file mode 100644 index 0000000000..8f70451dc2 --- /dev/null +++ b/avm/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' + } + } + } +] From b03a1a7afe8cba76e62a0d538c0a7acab308e170 Mon Sep 17 00:00:00 2001 From: "Shihua Xiong (MSFT)" <138103031+NanaXiong00@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:15:32 +0800 Subject: [PATCH 59/93] feat: Add new ptn modules `avm/ptn/azd/acr-container-app` (#3234) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1221 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.acr-container-app](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.acr-container-app.yml/badge.svg?branch=ptn%2Fazd%2Fcontainer-app)](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.acr-container-app.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.ptn.azd.acr-container-app.yml | 88 + avm/ptn/azd/acr-container-app/README.md | 497 +++++ avm/ptn/azd/acr-container-app/main.bicep | 253 +++ avm/ptn/azd/acr-container-app/main.json | 1773 +++++++++++++++++ .../modules/registry-access.bicep | 32 + .../tests/e2e/defaults/dependencies.bicep | 14 + .../tests/e2e/defaults/main.test.bicep | 58 + avm/ptn/azd/acr-container-app/version.json | 7 + 10 files changed, 2724 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.acr-container-app.yml create mode 100644 avm/ptn/azd/acr-container-app/README.md create mode 100644 avm/ptn/azd/acr-container-app/main.bicep create mode 100644 avm/ptn/azd/acr-container-app/main.json create mode 100644 avm/ptn/azd/acr-container-app/modules/registry-access.bicep create mode 100644 avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/acr-container-app/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/acr-container-app/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5ccd0ea12d..3c01853658 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,6 +12,7 @@ #/avm/ptn/avd-lza/management-plane/ @Azure/avm-ptn-avd-lza-managementplane-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/networking/ @Azure/avm-ptn-avd-lza-networking-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/session-hosts/ @Azure/avm-ptn-avd-lza-sessionhosts-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/acr-container-app/ @Azure/avm-ptn-azd-acrcontainerapp-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 486e96195c..5beb6c6247 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -47,6 +47,7 @@ body: # - "avm/ptn/avd-lza/management-plane" # - "avm/ptn/avd-lza/networking" # - "avm/ptn/avd-lza/session-hosts" + - "avm/ptn/azd/acr-container-app" - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" diff --git a/.github/workflows/avm.ptn.azd.acr-container-app.yml b/.github/workflows/avm.ptn.azd.acr-container-app.yml new file mode 100644 index 0000000000..04a83ea855 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.acr-container-app.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.acr-container-app" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.acr-container-app.yml" + - "avm/ptn/azd/acr-container-app/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/acr-container-app" + workflowPath: ".github/workflows/avm.ptn.azd.acr-container-app.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/azd/acr-container-app/README.md b/avm/ptn/azd/acr-container-app/README.md new file mode 100644 index 0000000000..a2a8f79199 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/README.md @@ -0,0 +1,497 @@ +# Azd ACR Linked Container App `[Azd/AcrContainerApp]` + +Creates a container app in an Azure Container App environment. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case + +## 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.App/containerApps` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2024-03-01/containerApps) | +| `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) | + +## 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/azd/acr-container-app:`. + +- [Using only defaults](#example-1-using-only-defaults) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module acrContainerApp 'br/public:avm/ptn/azd/acr-container-app:' = { + name: 'acrContainerAppDeployment' + params: { + // Required parameters + containerAppsEnvironmentName: '' + name: 'acamin001' + // 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 + "containerAppsEnvironmentName": { + "value": "" + }, + "name": { + "value": "acamin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/acr-container-app:' + +// Required parameters +param containerAppsEnvironmentName = '' +param name = 'acamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerAppsEnvironmentName`](#parameter-containerappsenvironmentname) | string | Name of the environment for container apps. | +| [`name`](#parameter-name) | string | The name of the Container App. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedOrigins`](#parameter-allowedorigins) | array | Allowed origins. | +| [`containerCpuCoreCount`](#parameter-containercpucorecount) | string | CPU cores allocated to a single container instance, e.g., 0.5. | +| [`containerMaxReplicas`](#parameter-containermaxreplicas) | int | The maximum number of replicas to run. Must be at least 1. | +| [`containerMemory`](#parameter-containermemory) | string | Memory allocated to a single container instance, e.g., 1Gi. | +| [`containerMinReplicas`](#parameter-containerminreplicas) | int | The minimum number of replicas to run. Must be at least 2. | +| [`containerName`](#parameter-containername) | string | The name of the container. | +| [`containerRegistryHostSuffix`](#parameter-containerregistryhostsuffix) | string | Hostname suffix for container registry. Set when deploying to sovereign clouds. | +| [`containerRegistryName`](#parameter-containerregistryname) | string | The name of the container registry. | +| [`daprAppId`](#parameter-daprappid) | string | The Dapr app ID. | +| [`daprAppProtocol`](#parameter-daprappprotocol) | string | The protocol used by Dapr to connect to the app, e.g., http or grpc. | +| [`daprEnabled`](#parameter-daprenabled) | bool | Enable Dapr. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`env`](#parameter-env) | array | The environment variables for the container. | +| [`external`](#parameter-external) | bool | Specifies if the resource ingress is exposed externally. | +| [`identityName`](#parameter-identityname) | string | The name of the user-assigned identity. | +| [`identityType`](#parameter-identitytype) | string | The type of identity for the resource. | +| [`imageName`](#parameter-imagename) | string | The name of the container image. | +| [`includeAddOns`](#parameter-includeaddons) | bool | Toggle to include the service configuration. | +| [`ingressAllowInsecure`](#parameter-ingressallowinsecure) | bool | Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections. | +| [`ingressEnabled`](#parameter-ingressenabled) | bool | Specifies if Ingress is enabled for the container app. | +| [`ingressTransport`](#parameter-ingresstransport) | string | Ingress transport protocol. | +| [`ipSecurityRestrictions`](#parameter-ipsecurityrestrictions) | array | Rules to restrict incoming IP address. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`principalId`](#parameter-principalid) | string | The principal ID of the principal to assign the role to. | +| [`revisionMode`](#parameter-revisionmode) | string | Controls how active revisions are handled for the Container app. | +| [`secrets`](#parameter-secrets) | secureObject | The secrets required for the container. | +| [`serviceBinds`](#parameter-servicebinds) | array | The service binds associated with the container. | +| [`serviceType`](#parameter-servicetype) | string | The name of the container apps add-on to use. e.g. redis. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`targetPort`](#parameter-targetport) | int | The target port for the container. | +| [`userAssignedIdentityResourceId`](#parameter-userassignedidentityresourceid) | string | The resource id of the user-assigned identity. | + +### Parameter: `containerAppsEnvironmentName` + +Name of the environment for container apps. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the Container App. + +- Required: Yes +- Type: string + +### Parameter: `allowedOrigins` + +Allowed origins. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `containerCpuCoreCount` + +CPU cores allocated to a single container instance, e.g., 0.5. + +- Required: No +- Type: string +- Default: `'0.5'` + +### Parameter: `containerMaxReplicas` + +The maximum number of replicas to run. Must be at least 1. + +- Required: No +- Type: int +- Default: `10` + +### Parameter: `containerMemory` + +Memory allocated to a single container instance, e.g., 1Gi. + +- Required: No +- Type: string +- Default: `'1.0Gi'` + +### Parameter: `containerMinReplicas` + +The minimum number of replicas to run. Must be at least 2. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `containerName` + +The name of the container. + +- Required: No +- Type: string +- Default: `'main'` + +### Parameter: `containerRegistryHostSuffix` + +Hostname suffix for container registry. Set when deploying to sovereign clouds. + +- Required: No +- Type: string +- Default: `'azurecr.io'` + +### Parameter: `containerRegistryName` + +The name of the container registry. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `daprAppId` + +The Dapr app ID. + +- Required: No +- Type: string +- Default: `[parameters('containerName')]` + +### Parameter: `daprAppProtocol` + +The protocol used by Dapr to connect to the app, e.g., http or grpc. + +- Required: No +- Type: string +- Default: `'http'` +- Allowed: + ```Bicep + [ + 'grpc' + 'http' + ] + ``` + +### Parameter: `daprEnabled` + +Enable Dapr. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `env` + +The environment variables for the container. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-envname) | string | Environment variable name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`secretRef`](#parameter-envsecretref) | string | Name of the Container App secret from which to pull the environment variable value. | +| [`value`](#parameter-envvalue) | string | Non-secret environment variable value. | + +### Parameter: `env.name` + +Environment variable name. + +- Required: Yes +- Type: string + +### Parameter: `env.secretRef` + +Name of the Container App secret from which to pull the environment variable value. + +- Required: No +- Type: string + +### Parameter: `env.value` + +Non-secret environment variable value. + +- Required: No +- Type: string + +### Parameter: `external` + +Specifies if the resource ingress is exposed externally. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `identityName` + +The name of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `identityType` + +The type of identity for the resource. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'None' + 'SystemAssigned' + 'UserAssigned' + ] + ``` + +### Parameter: `imageName` + +The name of the container image. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `includeAddOns` + +Toggle to include the service configuration. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `ingressAllowInsecure` + +Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `ingressEnabled` + +Specifies if Ingress is enabled for the container app. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `ingressTransport` + +Ingress transport protocol. + +- Required: No +- Type: string +- Default: `'auto'` +- Allowed: + ```Bicep + [ + 'auto' + 'http' + 'http2' + 'tcp' + ] + ``` + +### Parameter: `ipSecurityRestrictions` + +Rules to restrict incoming IP address. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `principalId` + +The principal ID of the principal to assign the role to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `revisionMode` + +Controls how active revisions are handled for the Container app. + +- Required: No +- Type: string +- Default: `'Single'` +- Allowed: + ```Bicep + [ + 'Multiple' + 'Single' + ] + ``` + +### Parameter: `secrets` + +The secrets required for the container. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `serviceBinds` + +The service binds associated with the container. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `serviceType` + +The name of the container apps add-on to use. e.g. redis. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `targetPort` + +The target port for the container. + +- Required: No +- Type: int +- Default: `80` + +### Parameter: `userAssignedIdentityResourceId` + +The resource id of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `defaultDomain` | string | The Default domain of the Managed Environment. | +| `identityPrincipalId` | string | The principal ID of the identity. | +| `imageName` | string | The name of the container image. | +| `name` | string | The name of the Container App. | +| `resourceGroupName` | string | The name of the resource group the Container App was deployed into. | +| `resourceId` | string | The resource ID of the Container App. | +| `serviceBind` | object | The service binds associated with the container. | +| `uri` | string | The uri of the Container App. | + +## 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/ptn/authorization/resource-role-assignment:0.1.1` | Remote reference | +| `br/public:avm/res/app/container-app:0.10.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/ptn/azd/acr-container-app/main.bicep b/avm/ptn/azd/acr-container-app/main.bicep new file mode 100644 index 0000000000..2f600aacf9 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/main.bicep @@ -0,0 +1,253 @@ +metadata name = 'Azd ACR Linked Container App' +metadata description = '''Creates a container app in an Azure Container App environment. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the Container App.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Allowed origins.') +param allowedOrigins array = [] + +@description('Required. Name of the environment for container apps.') +param containerAppsEnvironmentName string + +@description('Optional. CPU cores allocated to a single container instance, e.g., 0.5.') +param containerCpuCoreCount string = '0.5' + +@description('Optional. The maximum number of replicas to run. Must be at least 1.') +@minValue(1) +param containerMaxReplicas int = 10 + +@description('Optional. Memory allocated to a single container instance, e.g., 1Gi.') +param containerMemory string = '1.0Gi' + +@description('Optional. The minimum number of replicas to run. Must be at least 2.') +param containerMinReplicas int = 2 + +@description('Optional. The name of the container.') +param containerName string = 'main' + +@description('Optional. The name of the container registry.') +param containerRegistryName string = '' + +@description('Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds.') +param containerRegistryHostSuffix string = 'azurecr.io' + +@description('Optional. The protocol used by Dapr to connect to the app, e.g., http or grpc.') +@allowed(['http', 'grpc']) +param daprAppProtocol string = 'http' + +@description('Optional. The Dapr app ID.') +param daprAppId string = containerName + +@description('Optional. Enable Dapr.') +param daprEnabled bool = false + +@description('Optional. The environment variables for the container.') +param env environmentType[]? + +@description('Optional. Specifies if the resource ingress is exposed externally.') +param external bool = true + +@description('Optional. The name of the user-assigned identity.') +param identityName string = '' + +@description('Optional. The type of identity for the resource.') +@allowed(['None', 'SystemAssigned', 'UserAssigned']) +param identityType string = 'None' + +@description('Optional. The name of the container image.') +param imageName string = '' + +@description('Optional. Specifies if Ingress is enabled for the container app.') +param ingressEnabled bool = true + +@allowed([ + 'auto' + 'http' + 'http2' + 'tcp' +]) +@description('Optional. Ingress transport protocol.') +param ingressTransport string = 'auto' + +@description('Optional. Rules to restrict incoming IP address.') +param ipSecurityRestrictions array = [] + +@description('Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections.') +param ingressAllowInsecure bool = true + +@allowed([ + 'Multiple' + 'Single' +]) +@description('Optional. Controls how active revisions are handled for the Container app.') +param revisionMode string = 'Single' + +@description('Optional. The secrets required for the container.') +@secure() +param secrets object = {} + +@description('Optional. The service binds associated with the container.') +param serviceBinds array = [] + +@description('Optional. The name of the container apps add-on to use. e.g. redis.') +param serviceType string = '' + +@description('Optional. The target port for the container.') +param targetPort int = 80 + +@description('Optional. Toggle to include the service configuration.') +param includeAddOns bool = false + +@description('Optional. The principal ID of the principal to assign the role to.') +param principalId string = '' + +@description('Optional. The resource id of the user-assigned identity.') +param userAssignedIdentityResourceId string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// Private registry support requires both an ACR name and a User Assigned managed identity +var usePrivateRegistry = !empty(identityName) && !empty(containerRegistryName) + +// Automatically set to `UserAssigned` when an `identityName` has been set +var normalizedIdentityType = !empty(identityName) ? 'UserAssigned' : identityType + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-acrcontainerapp.${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 containerApp 'br/public:avm/res/app/container-app:0.10.0' = { + name: '${uniqueString(deployment().name, location)}-container-app' + params: { + name: name + location: location + tags: tags + managedIdentities: !empty(identityName) && normalizedIdentityType == 'UserAssigned' + ? { userAssignedResourceIds: [userAssignedIdentityResourceId] } + : { systemAssigned: normalizedIdentityType == 'SystemAssigned' } + environmentResourceId: containerAppsEnvironment.id + activeRevisionsMode: revisionMode + disableIngress: !ingressEnabled + ingressExternal: external + ingressTargetPort: targetPort + ingressTransport: ingressTransport + ipSecurityRestrictions: ipSecurityRestrictions + ingressAllowInsecure: ingressAllowInsecure + corsPolicy: { + allowedOrigins: union(['https://portal.azure.com', 'https://ms.portal.azure.com'], allowedOrigins) + } + dapr: daprEnabled + ? { + enabled: true + appId: daprAppId + appProtocol: daprAppProtocol + appPort: ingressEnabled ? targetPort : 0 + } + : { enabled: false } + secrets: secrets + includeAddOns: includeAddOns + service: { type: serviceType } + registries: usePrivateRegistry + ? [ + { + server: '${containerRegistryName}.${containerRegistryHostSuffix}' + identity: userAssignedIdentityResourceId + } + ] + : [] + serviceBinds: serviceBinds + containers: [ + { + image: !empty(imageName) ? imageName : 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: containerName + env: env + resources: { + cpu: json(containerCpuCoreCount) + memory: containerMemory + } + } + ] + scaleMaxReplicas: containerMaxReplicas + scaleMinReplicas: containerMinReplicas + enableTelemetry: enableTelemetry + } + dependsOn: usePrivateRegistry ? [containerRegistryAccess] : [] +} + +module containerRegistryAccess 'modules/registry-access.bicep' = if (usePrivateRegistry) { + name: '${uniqueString(deployment().name, location)}-registry-access' + params: { + containerRegistryName: containerRegistryName + principalId: usePrivateRegistry ? principalId : '' + enableTelemetry: enableTelemetry + } +} + +resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' existing = { + name: containerAppsEnvironmentName +} + +@description('The name of the resource group the Container App was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The Default domain of the Managed Environment.') +output defaultDomain string = containerAppsEnvironment.properties.defaultDomain + +@description('The principal ID of the identity.') +output identityPrincipalId string = normalizedIdentityType == 'None' + ? '' + : (empty(identityName) ? containerApp.outputs.systemAssignedMIPrincipalId : principalId) + +@description('The name of the container image.') +output imageName string = imageName + +@description('The name of the Container App.') +output name string = containerApp.outputs.name + +@description('The service binds associated with the container.') +output serviceBind object = !empty(serviceType) + ? { serviceId: containerApp.outputs.resourceId, name: containerApp.outputs.name } + : {} + +@description('The uri of the Container App.') +output uri string = ingressEnabled ? 'https://${containerApp.outputs.fqdn}' : '' + +@description('The resource ID of the Container App.') +output resourceId string = containerApp.outputs.resourceId + +type environmentType = { + @description('Required. Environment variable name.') + name: string + + @description('Optional. Name of the Container App secret from which to pull the environment variable value.') + secretRef: string? + + @description('Optional. Non-secret environment variable value.') + value: string? +} diff --git a/avm/ptn/azd/acr-container-app/main.json b/avm/ptn/azd/acr-container-app/main.json new file mode 100644 index 0000000000..3aa2261a84 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/main.json @@ -0,0 +1,1773 @@ +{ + "$schema": "https://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": "8683355263365484382" + }, + "name": "Azd ACR Linked Container App", + "description": "Creates a container app in an Azure Container App environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "environmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Container App." + } + }, + "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." + } + }, + "allowedOrigins": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Allowed origins." + } + }, + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "Required. Name of the environment for container apps." + } + }, + "containerCpuCoreCount": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. CPU cores allocated to a single container instance, e.g., 0.5." + } + }, + "containerMaxReplicas": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. The maximum number of replicas to run. Must be at least 1." + } + }, + "containerMemory": { + "type": "string", + "defaultValue": "1.0Gi", + "metadata": { + "description": "Optional. Memory allocated to a single container instance, e.g., 1Gi." + } + }, + "containerMinReplicas": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The minimum number of replicas to run. Must be at least 2." + } + }, + "containerName": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "Optional. The name of the container." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container registry." + } + }, + "containerRegistryHostSuffix": { + "type": "string", + "defaultValue": "azurecr.io", + "metadata": { + "description": "Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds." + } + }, + "daprAppProtocol": { + "type": "string", + "defaultValue": "http", + "allowedValues": [ + "http", + "grpc" + ], + "metadata": { + "description": "Optional. The protocol used by Dapr to connect to the app, e.g., http or grpc." + } + }, + "daprAppId": { + "type": "string", + "defaultValue": "[parameters('containerName')]", + "metadata": { + "description": "Optional. The Dapr app ID." + } + }, + "daprEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable Dapr." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables for the container." + } + }, + "external": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the resource ingress is exposed externally." + } + }, + "identityName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the user-assigned identity." + } + }, + "identityType": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "SystemAssigned", + "UserAssigned" + ], + "metadata": { + "description": "Optional. The type of identity for the resource." + } + }, + "imageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container image." + } + }, + "ingressEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if Ingress is enabled for the container app." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "revisionMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets required for the container." + } + }, + "serviceBinds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service binds associated with the container." + } + }, + "serviceType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container apps add-on to use. e.g. redis." + } + }, + "targetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. The target port for the container." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "principalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The principal ID of the principal to assign the role to." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource id of the user-assigned identity." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "usePrivateRegistry": "[and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName'))))]", + "normalizedIdentityType": "[if(not(empty(parameters('identityName'))), 'UserAssigned', parameters('identityType'))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-acrcontainerapp.{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" + } + } + } + } + }, + "containerAppsEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2023-05-01", + "name": "[parameters('containerAppsEnvironmentName')]" + }, + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-app', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": "[if(and(not(empty(parameters('identityName'))), equals(variables('normalizedIdentityType'), 'UserAssigned')), createObject('value', createObject('userAssignedResourceIds', createArray(parameters('userAssignedIdentityResourceId')))), createObject('value', createObject('systemAssigned', equals(variables('normalizedIdentityType'), 'SystemAssigned'))))]", + "environmentResourceId": { + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('containerAppsEnvironmentName'))]" + }, + "activeRevisionsMode": { + "value": "[parameters('revisionMode')]" + }, + "disableIngress": { + "value": "[not(parameters('ingressEnabled'))]" + }, + "ingressExternal": { + "value": "[parameters('external')]" + }, + "ingressTargetPort": { + "value": "[parameters('targetPort')]" + }, + "ingressTransport": { + "value": "[parameters('ingressTransport')]" + }, + "ipSecurityRestrictions": { + "value": "[parameters('ipSecurityRestrictions')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": { + "value": { + "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" + } + }, + "dapr": "[if(parameters('daprEnabled'), createObject('value', createObject('enabled', true(), 'appId', parameters('daprAppId'), 'appProtocol', parameters('daprAppProtocol'), 'appPort', if(parameters('ingressEnabled'), parameters('targetPort'), 0))), createObject('value', createObject('enabled', false())))]", + "secrets": { + "value": "[parameters('secrets')]" + }, + "includeAddOns": { + "value": "[parameters('includeAddOns')]" + }, + "service": { + "value": { + "type": "[parameters('serviceType')]" + } + }, + "registries": "[if(variables('usePrivateRegistry'), createObject('value', createArray(createObject('server', format('{0}.{1}', parameters('containerRegistryName'), parameters('containerRegistryHostSuffix')), 'identity', parameters('userAssignedIdentityResourceId')))), createObject('value', createArray()))]", + "serviceBinds": { + "value": "[parameters('serviceBinds')]" + }, + "containers": { + "value": [ + { + "image": "[if(not(empty(parameters('imageName'))), parameters('imageName'), 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest')]", + "name": "[parameters('containerName')]", + "env": "[parameters('env')]", + "resources": { + "cpu": "[json(parameters('containerCpuCoreCount'))]", + "memory": "[parameters('containerMemory')]" + } + } + ] + }, + "scaleMaxReplicas": { + "value": "[parameters('containerMaxReplicas')]" + }, + "scaleMinReplicas": { + "value": "[parameters('containerMinReplicas')]" + }, + "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.29.47.4906", + "templateHash": "9894768173968934379" + }, + "name": "Container Apps", + "description": "This module deploys a Container App.", + "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 + }, + "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 + }, + "container": { + "type": "object", + "properties": { + "args": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command arguments." + } + }, + "command": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVar" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container environment variables." + } + }, + "image": { + "type": "string", + "metadata": { + "description": "Required. Container image tag." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Custom container name." + } + }, + "probes": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbe" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of probes for the container." + } + }, + "resources": { + "type": "object", + "metadata": { + "description": "Required. Container resource requirements." + } + }, + "volumeMounts": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeMount" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container volume mounts." + } + } + } + }, + "ingressPortMapping": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + } + }, + "serviceBind": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + } + }, + "environmentVar": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + }, + "containerAppProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGet", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocket", + "nullable": true, + "metadata": { + "description": "Optional. TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "nullable": true + }, + "containerAppProbeHttpGet": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItem" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + } + }, + "containerAppProbeHttpGetHeadersItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + } + }, + "containerAppProbeTcpSocket": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + } + }, + "volumeMount": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dev ContainerApp service type." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMapping" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": 10, + "metadata": { + "description": "Optional. Maximum number of container replicas. Defaults to 10 if not set." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "Optional. Minimum number of container replicas. Defaults to 3 if not set." + } + }, + "scaleRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Scaling rules." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBind" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "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." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this 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." + } + }, + "customDomains": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom domain bindings for Container App hostnames." + } + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "trafficLabel": { + "type": "string", + "defaultValue": "label-1", + "metadata": { + "description": "Optional. Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes." + } + }, + "trafficLatestRevision": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates that the traffic weight belongs to a latest stable revision." + } + }, + "trafficRevisionName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of a revision." + } + }, + "trafficWeight": { + "type": "int", + "defaultValue": 100, + "metadata": { + "description": "Optional. Traffic weight assigned to a revision." + } + }, + "dapr": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dapr configuration for the Container App." + } + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/container" + }, + "metadata": { + "description": "Required. List of container definitions for the Container App." + } + }, + "initContainersTemplate": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of specialized containers that run before app containers." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of volume definitions for the Container App." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + } + }, + "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)))))]" + } + ], + "secretList": "[if(not(empty(parameters('secrets'))), parameters('secrets').secureList, createArray())]", + "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": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.10.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" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[if(not(empty(parameters('dapr'))), parameters('dapr'), null())]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', if(not(empty(parameters('customDomains'))), parameters('customDomains'), null()), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', if(not(empty(parameters('ipSecurityRestrictions'))), parameters('ipSecurityRestrictions'), null()), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), createArray(createObject('label', parameters('trafficLabel'), 'latestRevision', parameters('trafficLatestRevision'), 'revisionName', parameters('trafficRevisionName'), 'weight', parameters('trafficWeight'))), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(and(parameters('includeAddOns'), not(empty(parameters('service')))), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[if(not(empty(parameters('registries'))), parameters('registries'), null())]", + "secrets": "[variables('secretList')]" + }, + "template": { + "containers": "[parameters('containers')]", + "initContainers": "[if(not(empty(parameters('initContainersTemplate'))), parameters('initContainersTemplate'), null())]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": { + "maxReplicas": "[parameters('scaleMaxReplicas')]", + "minReplicas": "[parameters('scaleMinReplicas')]", + "rules": "[if(not(empty(parameters('scaleRules'))), parameters('scaleRules'), null())]" + }, + "serviceBinds": "[if(and(parameters('includeAddOns'), not(empty(parameters('serviceBinds')))), parameters('serviceBinds'), null())]", + "volumes": "[if(not(empty(parameters('volumes'))), parameters('volumes'), null())]" + }, + "workloadProfileName": "[parameters('workloadProfileName')]" + } + }, + "containerApp_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.App/containerApps/{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": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.App/containerApps/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', 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": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('containerApp', '2024-03-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2024-03-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "containerAppsEnvironment", + "containerRegistryAccess" + ] + }, + "containerRegistryAccess": { + "condition": "[variables('usePrivateRegistry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-access', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerRegistryName": { + "value": "[parameters('containerRegistryName')]" + }, + "principalId": "[if(variables('usePrivateRegistry'), createObject('value', parameters('principalId')), createObject('value', ''))]", + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "9239508313239206967" + }, + "name": "ACR Pull permissions", + "description": "Assigns ACR Pull permissions to access an Azure Container Registry.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the container registry." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "acrPullRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "acrpullrole-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[parameters('principalId')]" + }, + "resourceId": { + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]" + }, + "roleDefinitionId": { + "value": "[variables('acrPullRole')]" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "1847432691715853168" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource.", + "owner": "Azure/module-maintainers" + }, + "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('0.1.1', '.', '-'), 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]" + } + } + } + } + } + ] + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('containerAppsEnvironment').defaultDomain]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the identity." + }, + "value": "[if(equals(variables('normalizedIdentityType'), 'None'), '', if(empty(parameters('identityName')), reference('containerApp').outputs.systemAssignedMIPrincipalId.value, parameters('principalId')))]" + }, + "imageName": { + "type": "string", + "metadata": { + "description": "The name of the container image." + }, + "value": "[parameters('imageName')]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "serviceBind": { + "type": "object", + "metadata": { + "description": "The service binds associated with the container." + }, + "value": "[if(not(empty(parameters('serviceType'))), createObject('serviceId', reference('containerApp').outputs.resourceId.value, 'name', reference('containerApp').outputs.name.value), createObject())]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the Container App." + }, + "value": "[if(parameters('ingressEnabled'), format('https://{0}', reference('containerApp').outputs.fqdn.value), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/acr-container-app/modules/registry-access.bicep b/avm/ptn/azd/acr-container-app/modules/registry-access.bicep new file mode 100644 index 0000000000..3fdfe31799 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/modules/registry-access.bicep @@ -0,0 +1,32 @@ +metadata name = 'ACR Pull permissions' +metadata description = 'Assigns ACR Pull permissions to access an Azure Container Registry.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the container registry.') +param containerRegistryName string + +@description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') +param principalId string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var acrPullRole = subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7f951dda-4ed3-4680-a7ca-43fe172d538d' +) + +module aksAcrPull 'br/public:avm/ptn/authorization/resource-role-assignment:0.1.1' = { + name: 'acrpullrole-deployment' + params: { + principalId: principalId + resourceId: containerRegistry.id + roleDefinitionId: acrPullRole + principalType: 'ServicePrincipal' + enableTelemetry: enableTelemetry + } +} + +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' existing = { + name: containerRegistryName +} diff --git a/avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..6c93d0689b --- /dev/null +++ b/avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,14 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: {} +} + +@description('The name of the Container Apps environment.') +output containerAppsEnvironmentName string = managedEnvironment.name diff --git a/avm/ptn/azd/acr-container-app/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/acr-container-app/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..caa47bc42f --- /dev/null +++ b/avm/ptn/azd/acr-container-app/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}-azd-acrcontainerapp-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acamin' + +@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 + managedEnvironmentName: 'dep-${namePrefix}-me-${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' + containerAppsEnvironmentName: nestedDependencies.outputs.containerAppsEnvironmentName + location: resourceLocation + } + } +] diff --git a/avm/ptn/azd/acr-container-app/version.json b/avm/ptn/azd/acr-container-app/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/acr-container-app/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 6b63b1051ff4e19261a414acc829f6278ac8c3a1 Mon Sep 17 00:00:00 2001 From: "Jianing Wang (MSFT)" <141212663+jianingwang123@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:21:21 +0800 Subject: [PATCH 60/93] feat: Add new ptn modules `avm/ptn/azd/monitoring` (#3255) ## Description Fixes [Azure/Azure-Verified-Modules/issues#1226](https://github.com/Azure/Azure-Verified-Modules/issues/1226) ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.monitoring](https://github.com/jianingwang123/bicep-registry-modules/actions/workflows/avm.ptn.azd.monitoring.yml/badge.svg?branch=fix%2F1226)](https://github.com/jianingwang123/bicep-registry-modules/actions/workflows/avm.ptn.azd.monitoring.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.ptn.azd.monitoring.yml | 88 + avm/ptn/azd/monitoring/README.md | 208 + avm/ptn/azd/monitoring/main.bicep | 102 + avm/ptn/azd/monitoring/main.json | 4604 +++++++++++++++++ .../tests/e2e/defaults/main.test.bicep | 46 + avm/ptn/azd/monitoring/version.json | 7 + 8 files changed, 5057 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.monitoring.yml create mode 100644 avm/ptn/azd/monitoring/README.md create mode 100644 avm/ptn/azd/monitoring/main.bicep create mode 100644 avm/ptn/azd/monitoring/main.json create mode 100644 avm/ptn/azd/monitoring/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/monitoring/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3c01853658..2167ffc054 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,6 +17,7 @@ /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/monitoring/ @Azure/avm-ptn-azd-monitoring-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/dev-ops/cicd-agents-and-runners/ @Azure/avm-ptn-devops-cicdagentsandrunners-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/finops-toolkit/finops-hub/ @Azure/avm-ptn-finopstoolkit-finopshub-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 5beb6c6247..a74c246995 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -52,6 +52,7 @@ body: - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - "avm/ptn/azd/ml-hub-dependencies" + - "avm/ptn/azd/monitoring" - "avm/ptn/deployment-script/import-image-to-acr" - "avm/ptn/dev-ops/cicd-agents-and-runners" - "avm/ptn/finops-toolkit/finops-hub" diff --git a/.github/workflows/avm.ptn.azd.monitoring.yml b/.github/workflows/avm.ptn.azd.monitoring.yml new file mode 100644 index 0000000000..bba2cd1314 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.monitoring.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.monitoring" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.monitoring" + - "avm/ptn/azd/monitoring/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/monitoring" + workflowPath: ".github/workflows/avm.ptn.azd.monitoring.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit \ No newline at end of file diff --git a/avm/ptn/azd/monitoring/README.md b/avm/ptn/azd/monitoring/README.md new file mode 100644 index 0000000000..69f80aaf24 --- /dev/null +++ b/avm/ptn/azd/monitoring/README.md @@ -0,0 +1,208 @@ +# Azd Azure Monitoring `[Azd/Monitoring]` + +Creates an Application Insights instance and a Log Analytics workspace. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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) | +| `Microsoft.OperationalInsights/workspaces` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-01/workspaces) | +| `Microsoft.OperationalInsights/workspaces/dataExports` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataExports) | +| `Microsoft.OperationalInsights/workspaces/dataSources` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataSources) | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedServices) | +| `Microsoft.OperationalInsights/workspaces/linkedStorageAccounts` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedStorageAccounts) | +| `Microsoft.OperationalInsights/workspaces/savedSearches` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/savedSearches) | +| `Microsoft.OperationalInsights/workspaces/storageInsightConfigs` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/storageInsightConfigs) | +| `Microsoft.OperationalInsights/workspaces/tables` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-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.Portal/dashboards` | [2020-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Portal/2020-09-01-preview/dashboards) | + +## 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/azd/monitoring:`. + +- [Using only defaults](#example-1-using-only-defaults) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module monitoring 'br/public:avm/ptn/azd/monitoring:' = { + name: 'monitoringDeployment' + params: { + // Required parameters + applicationInsightsName: '' + logAnalyticsName: '' + // 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 + "applicationInsightsName": { + "value": "" + }, + "logAnalyticsName": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/monitoring:' + +// Required parameters +param applicationInsightsName = '' +param logAnalyticsName = '' +// Non-required parameters +param location = '' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationInsightsName`](#parameter-applicationinsightsname) | string | The resource insights components name. | +| [`logAnalyticsName`](#parameter-loganalyticsname) | string | The resource operational insights workspaces name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationInsightsDashboardName`](#parameter-applicationinsightsdashboardname) | string | The resource portal dashboards name. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `applicationInsightsName` + +The resource insights components name. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsName` + +The resource operational insights workspaces name. + +- Required: Yes +- Type: string + +### Parameter: `applicationInsightsDashboardName` + +The resource portal dashboards name. + +- 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: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + "key1": "value1" + "key2": "value2" + } + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `applicationInsightsConnectionString` | string | The connection string of the application insights. | +| `applicationInsightsInstrumentationKey` | string | The instrumentation key for the application insights. | +| `applicationInsightsName` | string | The name of the application insights. | +| `applicationInsightsResourceId` | string | The resource ID of the application insights. | +| `logAnalyticsWorkspaceName` | string | The name of the log analytics workspace. | +| `logAnalyticsWorkspaceResourceId` | string | The resource ID of the loganalytics workspace. | +| `resourceGroupName` | string | The resource group the operational-insights monitoring was deployed into. | + +## 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/ptn/azd/insights-dashboard:0.1.0` | Remote reference | +| `br/public:avm/res/operational-insights/workspace:0.7.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/ptn/azd/monitoring/main.bicep b/avm/ptn/azd/monitoring/main.bicep new file mode 100644 index 0000000000..6097ac2df3 --- /dev/null +++ b/avm/ptn/azd/monitoring/main.bicep @@ -0,0 +1,102 @@ +metadata name = 'Azd Azure Monitoring' +metadata description = '''Creates an Application Insights instance and a Log Analytics workspace. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The resource operational insights workspaces name.') +param logAnalyticsName string + +@description('Required. The resource insights components name.') +param applicationInsightsName string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. The resource portal dashboards name.') +param applicationInsightsDashboardName string = '' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-monitoring.${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 logAnalytics 'br/public:avm/res/operational-insights/workspace:0.7.0' = { + name: 'loganalytics' + params: { + name: logAnalyticsName + location: location + tags: tags + dataRetention: 30 + enableTelemetry: enableTelemetry + } +} + +module applicationInsights 'br/public:avm/ptn/azd/insights-dashboard:0.1.0' = { + name: 'applicationinsights' + params: { + logAnalyticsWorkspaceResourceId: logAnalytics.outputs.resourceId + name: applicationInsightsName + location: location + tags: tags + dashboardName: applicationInsightsDashboardName + enableTelemetry: enableTelemetry + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource group the operational-insights monitoring was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The connection string of the application insights.') +output applicationInsightsConnectionString string = applicationInsights.outputs.applicationInsightsConnectionString + +@description('The resource ID of the application insights.') +output applicationInsightsResourceId string = applicationInsights.outputs.applicationInsightsResourceId + +@description('The instrumentation key for the application insights.') +output applicationInsightsInstrumentationKey string = applicationInsights.outputs.applicationInsightsInstrumentationKey + +@description('The name of the application insights.') +output applicationInsightsName string = applicationInsights.outputs.applicationInsightsName + +@description('The resource ID of the loganalytics workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalytics.outputs.resourceId + +@description('The name of the log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalytics.outputs.name diff --git a/avm/ptn/azd/monitoring/main.json b/avm/ptn/azd/monitoring/main.json new file mode 100644 index 0000000000..9ed61ab0a1 --- /dev/null +++ b/avm/ptn/azd/monitoring/main.json @@ -0,0 +1,4604 @@ +{ + "$schema": "https://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": "2617595057203001759" + }, + "name": "Azd Azure Monitoring", + "description": "Creates an Application Insights instance and a Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Required. The resource operational insights workspaces name." + } + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "applicationInsightsDashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-monitoring.{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" + } + } + } + } + }, + "logAnalytics": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "loganalytics", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('logAnalyticsName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": 30 + }, + "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.29.47.4906", + "templateHash": "11627784326487264389" + }, + "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 + }, + "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." + } + }, + "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." + } + } + } + }, + "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." + } + }, + "linkedServices": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "defaultValue": [], + "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", + "defaultValue": [], + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics 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." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "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", + "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)))))]" + } + ], + "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('0.7.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": { + "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_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_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(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": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'tables')]" + }, + "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.29.47.4906", + "templateHash": "1745671120474305926" + }, + "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]" + } + }, + "dependsOn": [ + "storageAccount", + "workspace" + ] + } + }, + "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(parameters('linkedServices'))]" + }, + "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": "[parameters('linkedServices')[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(parameters('linkedServices')[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(parameters('linkedServices')[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.29.47.4906", + "templateHash": "12032441371027552374" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service.", + "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", + "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'))]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('linkedStorageAccounts'))]" + }, + "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": "[parameters('linkedStorageAccounts')[copyIndex()].name]" + }, + "resourceId": { + "value": "[parameters('linkedStorageAccounts')[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.29.47.4906", + "templateHash": "12623216644328477682" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account.", + "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", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": [ + "[parameters('resourceId')]" + ] + } + } + ], + "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(parameters('savedSearches'))]" + }, + "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}', parameters('savedSearches')[copyIndex()].name, uniqueString(deployment().name))]" + }, + "etag": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[parameters('savedSearches')[copyIndex()].displayName]" + }, + "category": { + "value": "[parameters('savedSearches')[copyIndex()].category]" + }, + "query": { + "value": "[parameters('savedSearches')[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionParameters')]" + }, + "version": { + "value": "[tryGet(parameters('savedSearches')[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.29.47.4906", + "templateHash": "7683333179440464721" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search.", + "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", + "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": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-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')]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('dataExports'))]" + }, + "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": "[parameters('dataExports')[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5765609820817623497" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export.", + "owner": "Azure/module-maintainers" + }, + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2020-08-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(parameters('dataSources'))]" + }, + "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": "[parameters('dataSources')[copyIndex()].name]" + }, + "kind": { + "value": "[parameters('dataSources')[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'performanceCounters')]" + } + }, + "template": { + "$schema": "https://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": "13460038983765020046" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source.", + "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", + "metadata": { + "description": "Required. Name of the solution." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Required. The kind of the DataSource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "linkedResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "defaultValue": "", + "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", + "defaultValue": "", + "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", + "defaultValue": "", + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "defaultValue": "", + "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": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2020-08-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())]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('tables'))]" + }, + "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": "[parameters('tables')[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'searchResults')]" + }, + "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.29.47.4906", + "templateHash": "10380077652898392916" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table.", + "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 + } + }, + "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": { + "type": "object", + "defaultValue": {}, + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "type": "object", + "defaultValue": {}, + "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": { + "$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')]", + "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": "2022-10-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-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')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "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(parameters('gallerySolutions'))]" + }, + "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": "[parameters('gallerySolutions')[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "product": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'product')]" + }, + "publisher": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'publisher')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('gallerySolutions')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "18444780972506374592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution. For Microsoft published gallery solution the target solution resource name will be composed as `{name}({logAnalyticsWorkspaceName})`." + } + }, + "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." + } + }, + "product": { + "type": "string", + "defaultValue": "OMSGallery", + "metadata": { + "description": "Optional. The product of the deployed solution. For Microsoft published gallery solution it should be `OMSGallery` and the target solution resource product will be composed as `OMSGallery/{name}`. For third party solution, it can be anything. This is case sensitive." + } + }, + "publisher": { + "type": "string", + "defaultValue": "Microsoft", + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "solutionName": "[if(equals(parameters('publisher'), 'Microsoft'), format('{0}({1})', parameters('name'), parameters('logAnalyticsWorkspaceName')), parameters('name'))]", + "solutionProduct": "[if(equals(parameters('publisher'), 'Microsoft'), format('OMSGallery/{0}', parameters('name')), parameters('product'))]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[variables('solutionName')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[variables('solutionName')]", + "promotionCode": "", + "product": "[variables('solutionProduct')]", + "publisher": "[parameters('publisher')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[variables('solutionName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName'))]" + }, + "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(resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName')), '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', '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'), '')]" + } + } + } + } + }, + "applicationInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "applicationinsights", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceResourceId": { + "value": "[reference('logAnalytics').outputs.resourceId.value]" + }, + "name": { + "value": "[parameters('applicationInsightsName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dashboardName": { + "value": "[parameters('applicationInsightsDashboardName')]" + }, + "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.29.47.4906", + "templateHash": "17156187352453961206" + }, + "name": "Application Insights Components", + "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "dashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "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." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the loganalytics workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "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." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-insightsdashboard.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "applicationInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appinsights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('kind')]" + }, + "applicationType": { + "value": "[parameters('applicationType')]" + }, + "workspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://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": "10653241142071426932" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance.", + "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 + }, + "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. 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", + "defaultValue": "", + "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." + } + }, + "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." + } + }, + "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." + } + }, + "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')]", + "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('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" + } + } + } + } + }, + "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')]" + } + }, + "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_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": "[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.29.47.4906", + "templateHash": "216781367921725873" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account.", + "owner": "Azure/module-maintainers" + }, + "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]" + } + } + } + } + }, + "applicationInsightsDashboard": { + "condition": "[not(empty(parameters('dashboardName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "application-insights-dashboard", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('dashboardName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "applicationInsightsName": { + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "applicationInsightsResourceId": { + "value": "[reference('applicationInsights').outputs.resourceId.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.29.47.4906", + "templateHash": "9856731218551847403" + }, + "name": "Azure Portal Dashboard", + "description": "Creates a dashboard for an Application Insights instance.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The portal dashboard name." + } + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components ID." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "dashboard": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "dashboard-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "lenses": { + "value": [ + { + "order": 0, + "parts": [ + { + "position": { + "x": 0, + "y": 0, + "colSpan": 2, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "id", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart", + "asset": { + "idInputName": "id", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "overview" + } + }, + { + "position": { + "x": 2, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "ProactiveDetection" + } + }, + { + "position": { + "x": 3, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + } + ], + "type": "Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:20:33.345Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 5, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-08T18:47:35.237Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "ConfigurationId", + "value": "78ce933e-e864-4b05-a27b-71fd55a6afad" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AppMapButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 0, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Usage", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 3, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:22:35.782Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + } + ], + "type": "Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Reliability", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 7, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:42:40.072Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "failures" + } + }, + { + "position": { + "x": 8, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Responsiveness\r\n", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 11, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:43:37.804Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "2a8ede4f-2bee-4b9c-aed9-2db0e8a01865", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "performance" + } + }, + { + "position": { + "x": 12, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Browser", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 15, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "MetricsExplorerJsonDefinitionId", + "value": "BrowserPerformanceTimelineMetrics" + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "createdTime": "2018-05-08T12:16:27.534Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "CurrentFilter", + "value": { + "eventTypes": [ + 4, + 1, + 3, + 5, + 2, + 6, + 13 + ], + "typeFacets": {}, + "isPermissive": false + } + }, + { + "name": "id", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "browser" + } + }, + { + "position": { + "x": 0, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "sessions/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Sessions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "users/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Users", + "color": "#7E58FF" + } + } + ], + "title": "Unique sessions and users", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "segmentationUsers" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Failed requests", + "color": "#EC008C" + } + } + ], + "title": "Failed requests", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "failures" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/duration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server response time", + "color": "#00BCF2" + } + } + ], + "title": "Server response time", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "performance" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/networkDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Page load network connect time", + "color": "#7E58FF" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/processingDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Client processing time", + "color": "#44F1C8" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/sendDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Send request time", + "color": "#EB9371" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/receiveDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Receiving response time", + "color": "#0672F1" + } + } + ], + "title": "Average page load time breakdown", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/availabilityPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability", + "color": "#47BDF5" + } + } + ], + "title": "Average availability", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "availability" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/server", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server exceptions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "dependencies/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Dependency failures", + "color": "#7E58FF" + } + } + ], + "title": "Server exceptions and Dependency failures", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processorCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Processor time", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process CPU", + "color": "#7E58FF" + } + } + ], + "title": "Average processor and process CPU utilization", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/browser", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Browser exceptions", + "color": "#47BDF5" + } + } + ], + "title": "Browser exceptions", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/count", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability test results count", + "color": "#47BDF5" + } + } + ], + "title": "Availability test results count", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processIOBytesPerSecond", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process IO rate", + "color": "#47BDF5" + } + } + ], + "title": "Average process I/O rate", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/memoryAvailableBytes", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Available memory", + "color": "#47BDF5" + } + } + ], + "title": "Average available memory", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "12676032921679464791" + }, + "name": "Portal Dashboards", + "description": "This module deploys a Portal Dashboard.", + "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 + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the dashboard 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." + } + }, + "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." + } + }, + "lenses": { + "type": "array", + "items": { + "type": "object" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The dashboard lenses." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The dashboard metadata." + } + } + }, + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.portal-dashboard.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "dashboard": { + "type": "Microsoft.Portal/dashboards", + "apiVersion": "2020-09-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "lenses": "[parameters('lenses')]", + "metadata": "[parameters('metadata')]" + } + }, + "dashboard_roleAssignments": { + "copy": { + "name": "dashboard_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Portal/dashboards/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Portal/dashboards', 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": [ + "dashboard" + ] + }, + "dashboard_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.Portal/dashboards/{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": [ + "dashboard" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[resourceId('Microsoft.Portal/dashboards', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dashboard was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the dashboard." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the dashboard was deployed into." + }, + "value": "[reference('dashboard', '2020-09-01-preview', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[reference('dashboard').outputs.resourceId.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[reference('dashboard').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "applicationInsights" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights components were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardName.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardResourceId.value, '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[reference('applicationInsights').outputs.connectionString.value]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[reference('applicationInsights').outputs.instrumentationKey.value]" + } + } + } + }, + "dependsOn": [ + "logAnalytics" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the operational-insights monitoring was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsConnectionString.value]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsResourceId.value]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key for the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsInstrumentationKey.value]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsName.value]" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the loganalytics workspace." + }, + "value": "[reference('logAnalytics').outputs.resourceId.value]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the log analytics workspace." + }, + "value": "[reference('logAnalytics').outputs.name.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/monitoring/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/monitoring/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..6a1efa2c23 --- /dev/null +++ b/avm/ptn/azd/monitoring/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}-azd-monitoring-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ammin' + +@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: { + location: resourceLocation + logAnalyticsName: '${uniqueString(deployment().name, resourceLocation)}-test-log-analytics-${serviceShort}' + applicationInsightsName: '${uniqueString(deployment().name, resourceLocation)}-test-appinsights-${serviceShort}' + } +} diff --git a/avm/ptn/azd/monitoring/version.json b/avm/ptn/azd/monitoring/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/monitoring/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From f06337032c4595246698b33c0d63fbb1ef72b80d Mon Sep 17 00:00:00 2001 From: Salima-90 <103124614+Salima-90@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:32:18 +0100 Subject: [PATCH 61/93] feat: separate backup snapshot policies netapps (#3403) ## Description - ANF backup and snapshot policies have been separated into their own modules ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.net-app.net-app-account](https://github.com/Salima-90/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml/badge.svg)](https://github.com/Salima-90/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml) | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- .../net-app-account/backup-policies/README.md | 98 +++ .../backup-policies/main.bicep | 48 ++ .../net-app-account/backup-policies/main.json | 97 +++ .../net-app-account/capacity-pool/README.md | 10 + .../net-app-account/capacity-pool/main.bicep | 2 + .../net-app-account/capacity-pool/main.json | 669 +++++++++++++---- .../capacity-pool/volume/README.md | 56 +- .../capacity-pool/volume/main.bicep | 196 ++--- .../capacity-pool/volume/main.json | 659 +++++++++++++---- avm/res/net-app/net-app-account/main.json | 673 ++++++++++++++---- .../snapshot-policies/README.md | 205 ++++++ .../snapshot-policies/main.bicep | 113 +++ .../snapshot-policies/main.json | 204 ++++++ 13 files changed, 2499 insertions(+), 531 deletions(-) create mode 100644 avm/res/net-app/net-app-account/backup-policies/README.md create mode 100644 avm/res/net-app/net-app-account/backup-policies/main.bicep create mode 100644 avm/res/net-app/net-app-account/backup-policies/main.json create mode 100644 avm/res/net-app/net-app-account/snapshot-policies/README.md create mode 100644 avm/res/net-app/net-app-account/snapshot-policies/main.bicep create mode 100644 avm/res/net-app/net-app-account/snapshot-policies/main.json diff --git a/avm/res/net-app/net-app-account/backup-policies/README.md b/avm/res/net-app/net-app-account/backup-policies/README.md new file mode 100644 index 0000000000..6756951c04 --- /dev/null +++ b/avm/res/net-app/net-app-account/backup-policies/README.md @@ -0,0 +1,98 @@ +# 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-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-03-01/netAppAccounts/backupPolicies) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backupPolicyName`](#parameter-backuppolicyname) | string | The name of the backup policy. | + +**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 | +| :-- | :-- | :-- | +| [`backupEnabled`](#parameter-backupenabled) | bool | Indicates whether the backup policy is enabled. | +| [`backupPolicyLocation`](#parameter-backuppolicylocation) | string | The location of the backup policy. Required if the template is used in a standalone deployment. | +| [`dailyBackupsToKeep`](#parameter-dailybackupstokeep) | int | The daily backups to keep. | +| [`monthlyBackupsToKeep`](#parameter-monthlybackupstokeep) | int | The monthly backups to keep. | +| [`weeklyBackupsToKeep`](#parameter-weeklybackupstokeep) | int | The weekly backups to keep. | + +### Parameter: `backupPolicyName` + +The name of the backup policy. + +- Required: No +- Type: string +- Default: `'backupPolicy'` + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `backupEnabled` + +Indicates whether the backup policy is enabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `backupPolicyLocation` + +The location of the backup policy. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `dailyBackupsToKeep` + +The daily backups to keep. + +- Required: Yes +- Type: int + +### Parameter: `monthlyBackupsToKeep` + +The monthly backups to keep. + +- Required: Yes +- Type: int + +### Parameter: `weeklyBackupsToKeep` + +The weekly backups to keep. + +- Required: Yes +- Type: int + +## 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/res/net-app/net-app-account/backup-policies/main.bicep b/avm/res/net-app/net-app-account/backup-policies/main.bicep new file mode 100644 index 0000000000..5a254eadfb --- /dev/null +++ b/avm/res/net-app/net-app-account/backup-policies/main.bicep @@ -0,0 +1,48 @@ +metadata name = 'Azure NetApp Files Backup Policy' +metadata description = 'This module deploys a Backup Policy for Azure NetApp File.' +metadata owner = 'Azure/module-maintainers' + +@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 backup policy.') +param backupPolicyName string = 'backupPolicy' + +@description('Optional. The location of the backup policy. Required if the template is used in a standalone deployment.') +param backupPolicyLocation string + +@description('Optional. The daily backups to keep.') +param dailyBackupsToKeep int + +@description('Optional. The monthly backups to keep.') +param monthlyBackupsToKeep int + +@description('Optional. The weekly backups to keep.') +param weeklyBackupsToKeep int + +@description('Optional. Indicates whether the backup policy is enabled.') +param backupEnabled bool = false + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-03-01' existing = { + name: netAppAccountName +} + +resource backupPolicies 'Microsoft.NetApp/netAppAccounts/backupPolicies@2024-03-01' = { + name: backupPolicyName + parent: netAppAccount + location: backupPolicyLocation + properties: { + dailyBackupsToKeep: dailyBackupsToKeep + enabled: backupEnabled + monthlyBackupsToKeep: monthlyBackupsToKeep + weeklyBackupsToKeep: weeklyBackupsToKeep + } +} +@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/res/net-app/net-app-account/backup-policies/main.json b/avm/res/net-app/net-app-account/backup-policies/main.json new file mode 100644 index 0000000000..315e53cdee --- /dev/null +++ b/avm/res/net-app/net-app-account/backup-policies/main.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "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('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "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/res/net-app/net-app-account/capacity-pool/README.md b/avm/res/net-app/net-app-account/capacity-pool/README.md index 4c95a9ca0b..888ae5f9ef 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/README.md @@ -7,6 +7,7 @@ This module deploys an Azure NetApp Files Capacity Pool. - [Resource Types](#Resource-Types) - [Parameters](#Parameters) - [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) ## Resource Types @@ -268,3 +269,12 @@ List of volumnes to create in 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. | | `volumeResourceId` | string | 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 | +| :-- | :-- | +| `res/net-app/net-app-account/backup-policies` | Local reference | +| `res/net-app/net-app-account/snapshot-policies` | Local reference | diff --git a/avm/res/net-app/net-app-account/capacity-pool/main.bicep b/avm/res/net-app/net-app-account/capacity-pool/main.bicep index 3fafb3a6cd..05ee747227 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/main.bicep +++ b/avm/res/net-app/net-app-account/capacity-pool/main.bicep @@ -157,6 +157,8 @@ module capacityPool_volumes 'volume/main.bicep' = [ useExistingSnapshot: volume.?useExistingSnapshot ?? false volumeResourceId: volume.?volumeResourceId ?? '' volumeType: volume.?volumeType ?? '' + backupVaultId: volume.?backupVaultId ?? '' + replicationEnabled: volume.?replicationEnabled ?? false } } ] diff --git a/avm/res/net-app/net-app-account/capacity-pool/main.json b/avm/res/net-app/net-app-account/capacity-pool/main.json index 34b2885f71..51024b061a 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/main.json +++ b/avm/res/net-app/net-app-account/capacity-pool/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8361786183534097212" + "version": "0.30.3.12046", + "templateHash": "5120059204101466005" }, "name": "Azure NetApp Files Capacity Pools", "description": "This module deploys an Azure NetApp Files Capacity Pool.", @@ -431,6 +431,12 @@ }, "volumeType": { "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'volumeType'), '')]" + }, + "backupVaultId": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'backupVaultId'), '')]" + }, + "replicationEnabled": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'replicationEnabled'), false())]" } }, "template": { @@ -440,8 +446,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18098024822158530053" + "version": "0.30.3.12046", + "templateHash": "3878108397799577614" }, "name": "Azure NetApp Files Capacity Pool Volumes", "description": "This module deploys an Azure NetApp Files Capacity Pool Volume.", @@ -604,88 +610,6 @@ "description": "Optional. The name of the backup policy." } }, - "backupPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backupVaultLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup vault." - } - }, - "backupName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupLabel": { - "type": "string", - "metadata": { - "description": "Optional. The label of the backup." - } - }, - "useExistingSnapshot": { - "type": "bool", - "metadata": { - "description": "Optional. Indicates whether to use an existing snapshot." - } - }, - "snapshotName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "snapshotPolicyId": { - "type": "string", - "metadata": { - "description": "Optional. Snapshot Policy ResourceId." - } - }, - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot policy." - } - }, - "snapshotPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the snapshot policy." - } - }, "dailyHour": { "type": "int", "metadata": { @@ -790,11 +714,79 @@ }, "snapEnabled": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Indicates whether the snapshot policy is enabled." } }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backupVaultLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup vault." + } + }, + "backupName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupLabel": { + "type": "string", + "metadata": { + "description": "Optional. The label of the backup." + } + }, + "useExistingSnapshot": { + "type": "bool", + "metadata": { + "description": "Optional. Indicates whether to use an existing snapshot." + } + }, + "snapshotName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "snapshotPolicyId": { + "type": "string", + "metadata": { + "description": "Optional. The snapshot Policy id." + } + }, "volumeResourceId": { "type": "string", "metadata": { @@ -829,6 +821,25 @@ "description": "Optional. Zone where the volume will be placed." } }, + "policyEnforced": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If Backup policy is enforced." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The backup policy location." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of snashot policies." + } + }, "serviceLevel": { "type": "string", "defaultValue": "Standard", @@ -893,6 +904,19 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "backupVaultId": { + "type": "string", + "metadata": { + "description": "Optional. The Id of the Backup Vault." + } + }, + "replicationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Boolean to enable replication." + } } }, "variables": { @@ -932,64 +956,13 @@ "apiVersion": "2024-03-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', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), 'snapshot', createObject('snapshotPolicyId', parameters('snapshotPolicyId')))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", + "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', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', if(parameters('replicationEnabled'), createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), createObject()), 'backup', if(parameters('backupEnabled'), createObject('backupPolicyId', reference('backupPolicies').outputs.resourceId.value, 'policyEnforced', parameters('policyEnforced'), 'backupVaultId', parameters('backupVaultId')), createObject()), 'snapshot', if(parameters('snapEnabled'), createObject('snapshotPolicyId', reference('snapshotPolicies').outputs.resourceId.value), createObject()))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", "zones": "[parameters('zones')]", "dependsOn": [ - "netAppAccount::capacityPool" - ] - }, - "snapshotPolicies": { - "condition": "[parameters('snapEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", - "location": "[parameters('snapshotPolicyLocation')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": { - "hour": "[parameters('dailyHour')]", - "minute": "[parameters('dailyMinute')]", - "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", - "usedBytes": "[parameters('dailyUsedBytes')]" - }, - "hourlySchedule": { - "minute": "[parameters('hourlyMinute')]", - "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", - "usedBytes": "[parameters('hourlyUsedBytes')]" - }, - "monthlySchedule": { - "daysOfMonth": "[parameters('daysOfMonth')]", - "hour": "[parameters('monthlyHour')]", - "minute": "[parameters('monthlyMinute')]", - "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", - "usedBytes": "[parameters('monthlyUsedBytes')]" - }, - "weeklySchedule": { - "day": "[parameters('weeklyDay')]", - "hour": "[parameters('weeklyHour')]", - "minute": "[parameters('weeklyMinute')]", - "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", - "usedBytes": "[parameters('weeklyUsedBytes')]" - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "backupPolicies": { - "condition": "[parameters('backupEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", - "location": "[parameters('backupPolicyLocation')]", - "properties": { - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "enabled": "[parameters('backupEnabled')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" - }, - "dependsOn": [ - "netAppAccount" + "backupPolicies", + "backupVaults", + "netAppAccount::capacityPool", + "snapshotPolicies" ] }, "backupVaults": { @@ -1010,7 +983,8 @@ "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('backupName'))]", "properties": "[if(parameters('backupEnabled'), createObject('label', parameters('backupLabel'), 'snapshotName', parameters('snapshotName'), 'useExistingSnapshot', parameters('useExistingSnapshot'), 'volumeResourceId', parameters('volumeResourceId')), createObject())]", "dependsOn": [ - "backupVaults" + "backupVaults", + "volume" ] }, "volume_roleAssignments": { @@ -1034,6 +1008,413 @@ "dependsOn": [ "volume" ] + }, + "backupPolicies": { + "condition": "[parameters('backupEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('backupPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyBackupsToKeep": { + "value": "[parameters('dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[parameters('monthlyBackupsToKeep')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "weeklyBackupsToKeep": { + "value": "[parameters('weeklyBackupsToKeep')]" + }, + "backupEnabled": { + "value": "[parameters('backupEnabled')]" + }, + "backupPolicyLocation": { + "value": "[parameters('backupPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "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('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } + }, + "snapshotPolicies": { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[uniqueString(parameters('snapshotPolicyName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyHour": { + "value": "[parameters('dailyHour')]" + }, + "dailyMinute": { + "value": "[parameters('dailyMinute')]" + }, + "dailySnapshotsToKeep": { + "value": "[parameters('dailySnapshotsToKeep')]" + }, + "dailyUsedBytes": { + "value": "[parameters('dailyUsedBytes')]" + }, + "daysOfMonth": { + "value": "[parameters('daysOfMonth')]" + }, + "hourlyMinute": { + "value": "[parameters('hourlyMinute')]" + }, + "hourlySnapshotsToKeep": { + "value": "[parameters('hourlySnapshotsToKeep')]" + }, + "hourlyUsedBytes": { + "value": "[parameters('hourlyUsedBytes')]" + }, + "monthlyHour": { + "value": "[parameters('monthlyHour')]" + }, + "monthlyMinute": { + "value": "[parameters('monthlyMinute')]" + }, + "monthlySnapshotsToKeep": { + "value": "[parameters('monthlySnapshotsToKeep')]" + }, + "monthlyUsedBytes": { + "value": "[parameters('monthlyUsedBytes')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "snapshotPolicyName": { + "value": "[parameters('snapshotPolicyName')]" + }, + "weeklyDay": { + "value": "[parameters('weeklyDay')]" + }, + "weeklyHour": { + "value": "[parameters('weeklyHour')]" + }, + "weeklyMinute": { + "value": "[parameters('weeklyMinute')]" + }, + "weeklySnapshotsToKeep": { + "value": "[parameters('weeklySnapshotsToKeep')]" + }, + "weeklyUsedBytes": { + "value": "[parameters('weeklyUsedBytes')]" + }, + "snapshotPolicyLocation": { + "value": "[parameters('snapshotPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "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('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, "outputs": { diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md index 9361b0045e..de7e5a1c46 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md @@ -7,6 +7,7 @@ This module deploys an Azure NetApp Files Capacity Pool Volume. - [Resource Types](#Resource-Types) - [Parameters](#Parameters) - [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) ## Resource Types @@ -43,8 +44,9 @@ This module deploys an Azure NetApp Files Capacity Pool Volume. | [`backupEnabled`](#parameter-backupenabled) | bool | Indicates whether the backup policy is enabled. | | [`backupLabel`](#parameter-backuplabel) | string | The label of the backup. | | [`backupName`](#parameter-backupname) | string | The name of the backup. | -| [`backupPolicyLocation`](#parameter-backuppolicylocation) | string | The location of the backup policy. | +| [`backupPolicyLocation`](#parameter-backuppolicylocation) | string | The backup policy location. | | [`backupPolicyName`](#parameter-backuppolicyname) | string | The name of the backup policy. | +| [`backupVaultId`](#parameter-backupvaultid) | string | The Id of the Backup Vault. | | [`backupVaultLocation`](#parameter-backupvaultlocation) | string | The location of the backup vault. | | [`backupVaultName`](#parameter-backupvaultname) | string | The name of the backup vault. | | [`coolAccess`](#parameter-coolaccess) | bool | If enabled (true) the pool can contain cool Access enabled volumes. | @@ -71,16 +73,18 @@ This module deploys an Azure NetApp Files Capacity Pool Volume. | [`monthlySnapshotsToKeep`](#parameter-monthlysnapshotstokeep) | int | Monthly snapshot count to keep. | | [`monthlyUsedBytes`](#parameter-monthlyusedbytes) | int | Monthly snapshot used bytes. | | [`networkFeatures`](#parameter-networkfeatures) | string | Network feature for the volume. | +| [`policyEnforced`](#parameter-policyenforced) | bool | If Backup policy is enforced. | | [`protocolTypes`](#parameter-protocoltypes) | array | Set of protocol types. | | [`remoteVolumeRegion`](#parameter-remotevolumeregion) | string | The remote region for the other end of the Volume Replication. | | [`remoteVolumeResourceId`](#parameter-remotevolumeresourceid) | string | The resource ID of the remote volume. | +| [`replicationEnabled`](#parameter-replicationenabled) | bool | Boolean to enable replication. | | [`replicationSchedule`](#parameter-replicationschedule) | string | The replication schedule for the volume. | | [`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. | | [`snapEnabled`](#parameter-snapenabled) | bool | Indicates whether the snapshot policy is enabled. | | [`snapshotName`](#parameter-snapshotname) | string | The name of the snapshot. | -| [`snapshotPolicyId`](#parameter-snapshotpolicyid) | string | Snapshot Policy ResourceId. | -| [`snapshotPolicyLocation`](#parameter-snapshotpolicylocation) | string | The location of the snapshot policy. | +| [`snapshotPolicyId`](#parameter-snapshotpolicyid) | string | The snapshot Policy id. | +| [`snapshotPolicyLocation`](#parameter-snapshotpolicylocation) | string | The location of snashot policies. | | [`snapshotPolicyName`](#parameter-snapshotpolicyname) | string | The name of the snapshot policy. | | [`useExistingSnapshot`](#parameter-useexistingsnapshot) | bool | Indicates whether to use an existing snapshot. | | [`volumeResourceId`](#parameter-volumeresourceid) | string | The resource ID of the volume. | @@ -152,11 +156,10 @@ The name of the backup. ### Parameter: `backupPolicyLocation` -The location of the backup policy. +The backup policy location. -- Required: No +- Required: Yes - Type: string -- Default: `[resourceGroup().location]` ### Parameter: `backupPolicyName` @@ -166,6 +169,13 @@ The name of the backup policy. - Type: string - Default: `'backupPolicy'` +### Parameter: `backupVaultId` + +The Id of the Backup Vault. + +- Required: Yes +- Type: string + ### Parameter: `backupVaultLocation` The location of the backup vault. @@ -364,6 +374,14 @@ Network feature for the volume. ] ``` +### Parameter: `policyEnforced` + +If Backup policy is enforced. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `protocolTypes` Set of protocol types. @@ -386,6 +404,14 @@ The resource ID of the remote volume. - Required: Yes - Type: string +### Parameter: `replicationEnabled` + +Boolean to enable replication. + +- Required: No +- Type: bool +- Default: `True` + ### Parameter: `replicationSchedule` The replication schedule for the volume. @@ -519,7 +545,7 @@ Indicates whether the snapshot policy is enabled. - Required: No - Type: bool -- Default: `False` +- Default: `True` ### Parameter: `snapshotName` @@ -530,18 +556,17 @@ The name of the snapshot. ### Parameter: `snapshotPolicyId` -Snapshot Policy ResourceId. +The snapshot Policy id. - Required: Yes - Type: string ### Parameter: `snapshotPolicyLocation` -The location of the snapshot policy. +The location of snashot policies. -- Required: No +- Required: Yes - Type: string -- Default: `[resourceGroup().location]` ### Parameter: `snapshotPolicyName` @@ -634,3 +659,12 @@ Zone where the volume will be placed. | `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 | +| :-- | :-- | +| `res/net-app/net-app-account/backup-policies` | Local reference | +| `res/net-app/net-app-account/snapshot-policies` | Local reference | diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep b/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep index 8143e6e448..ce5de13b21 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep @@ -41,45 +41,6 @@ param backupEnabled bool = false @description('Optional. The name of the backup policy.') param backupPolicyName string = 'backupPolicy' -@description('Optional. The location of the backup policy.') -param backupPolicyLocation string = resourceGroup().location - -@description('Optional. The daily backups to keep.') -param dailyBackupsToKeep int - -@description('Optional. The monthly backups to keep.') -param monthlyBackupsToKeep int - -@description('Optional. The weekly backups to keep.') -param weeklyBackupsToKeep int - -@description('Optional. The name of the backup vault.') -param backupVaultName string = 'vault' - -@description('Optional. The location of the backup vault.') -param backupVaultLocation string = resourceGroup().location - -@description('Optional. The name of the backup.') -param backupName string - -@description('Optional. The label of the backup.') -param backupLabel string - -@description('Optional. Indicates whether to use an existing snapshot.') -param useExistingSnapshot bool - -@description('Optional. The name of the snapshot.') -param snapshotName string - -@description('Optional. Snapshot Policy ResourceId.') -param snapshotPolicyId string - -@description('Optional. The name of the snapshot policy.') -param snapshotPolicyName string - -@description('Optional. The location of the snapshot policy.') -param snapshotPolicyLocation string = resourceGroup().location - @description('Optional. The daily snapshot hour.') param dailyHour int @@ -132,7 +93,40 @@ param weeklySnapshotsToKeep int param weeklyUsedBytes int @description('Optional. Indicates whether the snapshot policy is enabled.') -param snapEnabled bool = false +param snapEnabled bool = true + +@description('Optional. The name of the snapshot policy.') +param snapshotPolicyName string + +@description('Optional. The daily backups to keep.') +param dailyBackupsToKeep int + +@description('Optional. The monthly backups to keep.') +param monthlyBackupsToKeep int + +@description('Optional. The weekly backups to keep.') +param weeklyBackupsToKeep int + +@description('Optional. The name of the backup vault.') +param backupVaultName string = 'vault' + +@description('Optional. The location of the backup vault.') +param backupVaultLocation string = resourceGroup().location + +@description('Optional. The name of the backup.') +param backupName string + +@description('Optional. The label of the backup.') +param backupLabel string + +@description('Optional. Indicates whether to use an existing snapshot.') +param useExistingSnapshot bool + +@description('Optional. The name of the snapshot.') +param snapshotName string + +@description('Optional. The snapshot Policy id.') +param snapshotPolicyId string @description('Optional. The resource ID of the volume.') param volumeResourceId string @@ -149,6 +143,15 @@ param location string = resourceGroup().location @description('Optional. Zone where the volume will be placed.') param zones array = ['1'] +@description('Optional. If Backup policy is enforced.') +param policyEnforced bool = false + +@description('Optional. The backup policy location.') +param backupPolicyLocation string + +@description('Optional. The location of snashot policies.') +param snapshotPolicyLocation string + @description('Optional. The pool service level. Must match the one of the parent capacity pool.') @allowed([ 'Premium' @@ -185,6 +188,12 @@ param exportPolicyRules array = [] @description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType +@description('Optional. The Id of the Backup Vault.') +param backupVaultId string + +@description('Optional. Boolean to enable replication.') +param replicationEnabled bool = true + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -222,6 +231,10 @@ resource volume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2024-03-0 name: name parent: netAppAccount::capacityPool location: location + dependsOn: [ + backupVaults + backupPolicies + ] properties: { coolAccess: coolAccess coolAccessRetrievalPolicy: coolAccessRetrievalPolicy @@ -236,15 +249,27 @@ resource volume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2024-03-0 ? { volumeType: volumeType dataProtection: { - replication: { - endpointType: endpointType - remoteVolumeRegion: remoteVolumeRegion - remoteVolumeResourceId: remoteVolumeResourceId - replicationSchedule: replicationSchedule - } - snapshot: { - snapshotPolicyId: snapshotPolicyId - } + replication: replicationEnabled + ? { + endpointType: endpointType + remoteVolumeRegion: remoteVolumeRegion + remoteVolumeResourceId: remoteVolumeResourceId + replicationSchedule: replicationSchedule + } + : {} + + backup: backupEnabled + ? { + backupPolicyId: backupPolicies.outputs.resourceId + policyEnforced: policyEnforced + backupVaultId: backupVaultId + } + : {} + snapshot: snapEnabled + ? { + snapshotPolicyId: snapshotPolicies.outputs.resourceId + } + : {} } } : {}) @@ -263,49 +288,41 @@ resource volume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2024-03-0 zones: zones } -resource snapshotPolicies 'Microsoft.NetApp/netAppAccounts/snapshotPolicies@2024-03-01' = if (snapEnabled) { - name: snapshotPolicyName - parent: netAppAccount - location: snapshotPolicyLocation - properties: { - enabled: snapEnabled - dailySchedule: { - hour: dailyHour - minute: dailyMinute - snapshotsToKeep: dailySnapshotsToKeep - usedBytes: dailyUsedBytes - } - hourlySchedule: { - minute: hourlyMinute - snapshotsToKeep: hourlySnapshotsToKeep - usedBytes: hourlyUsedBytes - } - monthlySchedule: { - daysOfMonth: daysOfMonth - hour: monthlyHour - minute: monthlyMinute - snapshotsToKeep: monthlySnapshotsToKeep - usedBytes: monthlyUsedBytes - } - weeklySchedule: { - day: weeklyDay - hour: weeklyHour - minute: weeklyMinute - snapshotsToKeep: weeklySnapshotsToKeep - usedBytes: weeklyUsedBytes - } - } -} - -resource backupPolicies 'Microsoft.NetApp/netAppAccounts/backupPolicies@2024-03-01' = if (backupEnabled) { +module backupPolicies '../../backup-policies/main.bicep' = if (backupEnabled) { name: backupPolicyName - parent: netAppAccount - location: backupPolicyLocation - properties: { + params: { dailyBackupsToKeep: dailyBackupsToKeep - enabled: backupEnabled monthlyBackupsToKeep: monthlyBackupsToKeep + netAppAccountName: netAppAccountName weeklyBackupsToKeep: weeklyBackupsToKeep + backupEnabled: backupEnabled + backupPolicyLocation: backupPolicyLocation + } +} + +module snapshotPolicies '../../snapshot-policies/main.bicep' = if (snapEnabled) { + name: uniqueString(snapshotPolicyName) + params: { + dailyHour: dailyHour + dailyMinute: dailyMinute + dailySnapshotsToKeep: dailySnapshotsToKeep + dailyUsedBytes: dailyUsedBytes + daysOfMonth: daysOfMonth + hourlyMinute: hourlyMinute + hourlySnapshotsToKeep: hourlySnapshotsToKeep + hourlyUsedBytes: hourlyUsedBytes + monthlyHour: monthlyHour + monthlyMinute: monthlyMinute + monthlySnapshotsToKeep: monthlySnapshotsToKeep + monthlyUsedBytes: monthlyUsedBytes + netAppAccountName: netAppAccountName + snapshotPolicyName: snapshotPolicyName + weeklyDay: weeklyDay + weeklyHour: weeklyHour + weeklyMinute: weeklyMinute + weeklySnapshotsToKeep: weeklySnapshotsToKeep + weeklyUsedBytes: weeklyUsedBytes + snapshotPolicyLocation: snapshotPolicyLocation } } @@ -319,6 +336,9 @@ resource backupVaults 'Microsoft.NetApp/netAppAccounts/backupVaults@2024-03-01' resource backups 'Microsoft.NetApp/netAppAccounts/backupVaults/backups@2024-03-01' = if (backupEnabled) { name: backupName parent: backupVaults + dependsOn: [ + volume + ] properties: backupEnabled ? { label: backupLabel diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/main.json b/avm/res/net-app/net-app-account/capacity-pool/volume/main.json index 0e32725463..dbbbaa682f 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/main.json +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18098024822158530053" + "version": "0.30.3.12046", + "templateHash": "3878108397799577614" }, "name": "Azure NetApp Files Capacity Pool Volumes", "description": "This module deploys an Azure NetApp Files Capacity Pool Volume.", @@ -169,88 +169,6 @@ "description": "Optional. The name of the backup policy." } }, - "backupPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backupVaultLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup vault." - } - }, - "backupName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupLabel": { - "type": "string", - "metadata": { - "description": "Optional. The label of the backup." - } - }, - "useExistingSnapshot": { - "type": "bool", - "metadata": { - "description": "Optional. Indicates whether to use an existing snapshot." - } - }, - "snapshotName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "snapshotPolicyId": { - "type": "string", - "metadata": { - "description": "Optional. Snapshot Policy ResourceId." - } - }, - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot policy." - } - }, - "snapshotPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the snapshot policy." - } - }, "dailyHour": { "type": "int", "metadata": { @@ -355,11 +273,79 @@ }, "snapEnabled": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Indicates whether the snapshot policy is enabled." } }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backupVaultLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup vault." + } + }, + "backupName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupLabel": { + "type": "string", + "metadata": { + "description": "Optional. The label of the backup." + } + }, + "useExistingSnapshot": { + "type": "bool", + "metadata": { + "description": "Optional. Indicates whether to use an existing snapshot." + } + }, + "snapshotName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "snapshotPolicyId": { + "type": "string", + "metadata": { + "description": "Optional. The snapshot Policy id." + } + }, "volumeResourceId": { "type": "string", "metadata": { @@ -394,6 +380,25 @@ "description": "Optional. Zone where the volume will be placed." } }, + "policyEnforced": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If Backup policy is enforced." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The backup policy location." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of snashot policies." + } + }, "serviceLevel": { "type": "string", "defaultValue": "Standard", @@ -458,6 +463,19 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "backupVaultId": { + "type": "string", + "metadata": { + "description": "Optional. The Id of the Backup Vault." + } + }, + "replicationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Boolean to enable replication." + } } }, "variables": { @@ -497,64 +515,13 @@ "apiVersion": "2024-03-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', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), 'snapshot', createObject('snapshotPolicyId', parameters('snapshotPolicyId')))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", + "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', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', if(parameters('replicationEnabled'), createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), createObject()), 'backup', if(parameters('backupEnabled'), createObject('backupPolicyId', reference('backupPolicies').outputs.resourceId.value, 'policyEnforced', parameters('policyEnforced'), 'backupVaultId', parameters('backupVaultId')), createObject()), 'snapshot', if(parameters('snapEnabled'), createObject('snapshotPolicyId', reference('snapshotPolicies').outputs.resourceId.value), createObject()))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", "zones": "[parameters('zones')]", "dependsOn": [ - "netAppAccount::capacityPool" - ] - }, - "snapshotPolicies": { - "condition": "[parameters('snapEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", - "location": "[parameters('snapshotPolicyLocation')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": { - "hour": "[parameters('dailyHour')]", - "minute": "[parameters('dailyMinute')]", - "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", - "usedBytes": "[parameters('dailyUsedBytes')]" - }, - "hourlySchedule": { - "minute": "[parameters('hourlyMinute')]", - "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", - "usedBytes": "[parameters('hourlyUsedBytes')]" - }, - "monthlySchedule": { - "daysOfMonth": "[parameters('daysOfMonth')]", - "hour": "[parameters('monthlyHour')]", - "minute": "[parameters('monthlyMinute')]", - "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", - "usedBytes": "[parameters('monthlyUsedBytes')]" - }, - "weeklySchedule": { - "day": "[parameters('weeklyDay')]", - "hour": "[parameters('weeklyHour')]", - "minute": "[parameters('weeklyMinute')]", - "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", - "usedBytes": "[parameters('weeklyUsedBytes')]" - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "backupPolicies": { - "condition": "[parameters('backupEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", - "location": "[parameters('backupPolicyLocation')]", - "properties": { - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "enabled": "[parameters('backupEnabled')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" - }, - "dependsOn": [ - "netAppAccount" + "backupPolicies", + "backupVaults", + "netAppAccount::capacityPool", + "snapshotPolicies" ] }, "backupVaults": { @@ -575,7 +542,8 @@ "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('backupName'))]", "properties": "[if(parameters('backupEnabled'), createObject('label', parameters('backupLabel'), 'snapshotName', parameters('snapshotName'), 'useExistingSnapshot', parameters('useExistingSnapshot'), 'volumeResourceId', parameters('volumeResourceId')), createObject())]", "dependsOn": [ - "backupVaults" + "backupVaults", + "volume" ] }, "volume_roleAssignments": { @@ -599,6 +567,413 @@ "dependsOn": [ "volume" ] + }, + "backupPolicies": { + "condition": "[parameters('backupEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('backupPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyBackupsToKeep": { + "value": "[parameters('dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[parameters('monthlyBackupsToKeep')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "weeklyBackupsToKeep": { + "value": "[parameters('weeklyBackupsToKeep')]" + }, + "backupEnabled": { + "value": "[parameters('backupEnabled')]" + }, + "backupPolicyLocation": { + "value": "[parameters('backupPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "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('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } + }, + "snapshotPolicies": { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[uniqueString(parameters('snapshotPolicyName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyHour": { + "value": "[parameters('dailyHour')]" + }, + "dailyMinute": { + "value": "[parameters('dailyMinute')]" + }, + "dailySnapshotsToKeep": { + "value": "[parameters('dailySnapshotsToKeep')]" + }, + "dailyUsedBytes": { + "value": "[parameters('dailyUsedBytes')]" + }, + "daysOfMonth": { + "value": "[parameters('daysOfMonth')]" + }, + "hourlyMinute": { + "value": "[parameters('hourlyMinute')]" + }, + "hourlySnapshotsToKeep": { + "value": "[parameters('hourlySnapshotsToKeep')]" + }, + "hourlyUsedBytes": { + "value": "[parameters('hourlyUsedBytes')]" + }, + "monthlyHour": { + "value": "[parameters('monthlyHour')]" + }, + "monthlyMinute": { + "value": "[parameters('monthlyMinute')]" + }, + "monthlySnapshotsToKeep": { + "value": "[parameters('monthlySnapshotsToKeep')]" + }, + "monthlyUsedBytes": { + "value": "[parameters('monthlyUsedBytes')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "snapshotPolicyName": { + "value": "[parameters('snapshotPolicyName')]" + }, + "weeklyDay": { + "value": "[parameters('weeklyDay')]" + }, + "weeklyHour": { + "value": "[parameters('weeklyHour')]" + }, + "weeklyMinute": { + "value": "[parameters('weeklyMinute')]" + }, + "weeklySnapshotsToKeep": { + "value": "[parameters('weeklySnapshotsToKeep')]" + }, + "weeklyUsedBytes": { + "value": "[parameters('weeklyUsedBytes')]" + }, + "snapshotPolicyLocation": { + "value": "[parameters('snapshotPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "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('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, "outputs": { diff --git a/avm/res/net-app/net-app-account/main.json b/avm/res/net-app/net-app-account/main.json index afe617cbcf..c260cb81ba 100644 --- a/avm/res/net-app/net-app-account/main.json +++ b/avm/res/net-app/net-app-account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5247980225087680814" + "version": "0.30.3.12046", + "templateHash": "6577593938028395411" }, "name": "Azure NetApp Files", "description": "This module deploys an Azure NetApp File.", @@ -503,8 +503,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8361786183534097212" + "version": "0.30.3.12046", + "templateHash": "5120059204101466005" }, "name": "Azure NetApp Files Capacity Pools", "description": "This module deploys an Azure NetApp Files Capacity Pool.", @@ -929,6 +929,12 @@ }, "volumeType": { "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'volumeType'), '')]" + }, + "backupVaultId": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'backupVaultId'), '')]" + }, + "replicationEnabled": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'replicationEnabled'), false())]" } }, "template": { @@ -938,8 +944,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18098024822158530053" + "version": "0.30.3.12046", + "templateHash": "3878108397799577614" }, "name": "Azure NetApp Files Capacity Pool Volumes", "description": "This module deploys an Azure NetApp Files Capacity Pool Volume.", @@ -1102,88 +1108,6 @@ "description": "Optional. The name of the backup policy." } }, - "backupPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backupVaultLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup vault." - } - }, - "backupName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupLabel": { - "type": "string", - "metadata": { - "description": "Optional. The label of the backup." - } - }, - "useExistingSnapshot": { - "type": "bool", - "metadata": { - "description": "Optional. Indicates whether to use an existing snapshot." - } - }, - "snapshotName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "snapshotPolicyId": { - "type": "string", - "metadata": { - "description": "Optional. Snapshot Policy ResourceId." - } - }, - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot policy." - } - }, - "snapshotPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the snapshot policy." - } - }, "dailyHour": { "type": "int", "metadata": { @@ -1288,11 +1212,79 @@ }, "snapEnabled": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Indicates whether the snapshot policy is enabled." } }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backupVaultLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup vault." + } + }, + "backupName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupLabel": { + "type": "string", + "metadata": { + "description": "Optional. The label of the backup." + } + }, + "useExistingSnapshot": { + "type": "bool", + "metadata": { + "description": "Optional. Indicates whether to use an existing snapshot." + } + }, + "snapshotName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "snapshotPolicyId": { + "type": "string", + "metadata": { + "description": "Optional. The snapshot Policy id." + } + }, "volumeResourceId": { "type": "string", "metadata": { @@ -1327,6 +1319,25 @@ "description": "Optional. Zone where the volume will be placed." } }, + "policyEnforced": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If Backup policy is enforced." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The backup policy location." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of snashot policies." + } + }, "serviceLevel": { "type": "string", "defaultValue": "Standard", @@ -1391,6 +1402,19 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "backupVaultId": { + "type": "string", + "metadata": { + "description": "Optional. The Id of the Backup Vault." + } + }, + "replicationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Boolean to enable replication." + } } }, "variables": { @@ -1430,64 +1454,13 @@ "apiVersion": "2024-03-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', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), 'snapshot', createObject('snapshotPolicyId', parameters('snapshotPolicyId')))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", + "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', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', if(parameters('replicationEnabled'), createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), createObject()), 'backup', if(parameters('backupEnabled'), createObject('backupPolicyId', reference('backupPolicies').outputs.resourceId.value, 'policyEnforced', parameters('policyEnforced'), 'backupVaultId', parameters('backupVaultId')), createObject()), 'snapshot', if(parameters('snapEnabled'), createObject('snapshotPolicyId', reference('snapshotPolicies').outputs.resourceId.value), createObject()))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", "zones": "[parameters('zones')]", "dependsOn": [ - "netAppAccount::capacityPool" - ] - }, - "snapshotPolicies": { - "condition": "[parameters('snapEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", - "location": "[parameters('snapshotPolicyLocation')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": { - "hour": "[parameters('dailyHour')]", - "minute": "[parameters('dailyMinute')]", - "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", - "usedBytes": "[parameters('dailyUsedBytes')]" - }, - "hourlySchedule": { - "minute": "[parameters('hourlyMinute')]", - "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", - "usedBytes": "[parameters('hourlyUsedBytes')]" - }, - "monthlySchedule": { - "daysOfMonth": "[parameters('daysOfMonth')]", - "hour": "[parameters('monthlyHour')]", - "minute": "[parameters('monthlyMinute')]", - "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", - "usedBytes": "[parameters('monthlyUsedBytes')]" - }, - "weeklySchedule": { - "day": "[parameters('weeklyDay')]", - "hour": "[parameters('weeklyHour')]", - "minute": "[parameters('weeklyMinute')]", - "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", - "usedBytes": "[parameters('weeklyUsedBytes')]" - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "backupPolicies": { - "condition": "[parameters('backupEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", - "location": "[parameters('backupPolicyLocation')]", - "properties": { - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "enabled": "[parameters('backupEnabled')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" - }, - "dependsOn": [ - "netAppAccount" + "backupPolicies", + "backupVaults", + "netAppAccount::capacityPool", + "snapshotPolicies" ] }, "backupVaults": { @@ -1508,7 +1481,8 @@ "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('backupName'))]", "properties": "[if(parameters('backupEnabled'), createObject('label', parameters('backupLabel'), 'snapshotName', parameters('snapshotName'), 'useExistingSnapshot', parameters('useExistingSnapshot'), 'volumeResourceId', parameters('volumeResourceId')), createObject())]", "dependsOn": [ - "backupVaults" + "backupVaults", + "volume" ] }, "volume_roleAssignments": { @@ -1532,6 +1506,413 @@ "dependsOn": [ "volume" ] + }, + "backupPolicies": { + "condition": "[parameters('backupEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('backupPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyBackupsToKeep": { + "value": "[parameters('dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[parameters('monthlyBackupsToKeep')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "weeklyBackupsToKeep": { + "value": "[parameters('weeklyBackupsToKeep')]" + }, + "backupEnabled": { + "value": "[parameters('backupEnabled')]" + }, + "backupPolicyLocation": { + "value": "[parameters('backupPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "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('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } + }, + "snapshotPolicies": { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[uniqueString(parameters('snapshotPolicyName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyHour": { + "value": "[parameters('dailyHour')]" + }, + "dailyMinute": { + "value": "[parameters('dailyMinute')]" + }, + "dailySnapshotsToKeep": { + "value": "[parameters('dailySnapshotsToKeep')]" + }, + "dailyUsedBytes": { + "value": "[parameters('dailyUsedBytes')]" + }, + "daysOfMonth": { + "value": "[parameters('daysOfMonth')]" + }, + "hourlyMinute": { + "value": "[parameters('hourlyMinute')]" + }, + "hourlySnapshotsToKeep": { + "value": "[parameters('hourlySnapshotsToKeep')]" + }, + "hourlyUsedBytes": { + "value": "[parameters('hourlyUsedBytes')]" + }, + "monthlyHour": { + "value": "[parameters('monthlyHour')]" + }, + "monthlyMinute": { + "value": "[parameters('monthlyMinute')]" + }, + "monthlySnapshotsToKeep": { + "value": "[parameters('monthlySnapshotsToKeep')]" + }, + "monthlyUsedBytes": { + "value": "[parameters('monthlyUsedBytes')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "snapshotPolicyName": { + "value": "[parameters('snapshotPolicyName')]" + }, + "weeklyDay": { + "value": "[parameters('weeklyDay')]" + }, + "weeklyHour": { + "value": "[parameters('weeklyHour')]" + }, + "weeklyMinute": { + "value": "[parameters('weeklyMinute')]" + }, + "weeklySnapshotsToKeep": { + "value": "[parameters('weeklySnapshotsToKeep')]" + }, + "weeklyUsedBytes": { + "value": "[parameters('weeklyUsedBytes')]" + }, + "snapshotPolicyLocation": { + "value": "[parameters('snapshotPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "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('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, "outputs": { diff --git a/avm/res/net-app/net-app-account/snapshot-policies/README.md b/avm/res/net-app/net-app-account/snapshot-policies/README.md new file mode 100644 index 0000000000..3fc4b313e2 --- /dev/null +++ b/avm/res/net-app/net-app-account/snapshot-policies/README.md @@ -0,0 +1,205 @@ +# 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-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-03-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 | +| :-- | :-- | :-- | +| [`dailyHour`](#parameter-dailyhour) | int | The daily snapshot hour. | +| [`dailyMinute`](#parameter-dailyminute) | int | The daily snapshot minute. | +| [`dailySnapshotsToKeep`](#parameter-dailysnapshotstokeep) | int | Daily snapshot count to keep. | +| [`dailyUsedBytes`](#parameter-dailyusedbytes) | int | Daily snapshot used bytes. | +| [`daysOfMonth`](#parameter-daysofmonth) | string | The monthly snapshot day. | +| [`hourlyMinute`](#parameter-hourlyminute) | int | The hourly snapshot minute. | +| [`hourlySnapshotsToKeep`](#parameter-hourlysnapshotstokeep) | int | Hourly snapshot count to keep. | +| [`hourlyUsedBytes`](#parameter-hourlyusedbytes) | int | Hourly snapshot used bytes. | +| [`monthlyHour`](#parameter-monthlyhour) | int | The monthly snapshot hour. | +| [`monthlyMinute`](#parameter-monthlyminute) | int | The monthly snapshot minute. | +| [`monthlySnapshotsToKeep`](#parameter-monthlysnapshotstokeep) | int | Monthly snapshot count to keep. | +| [`monthlyUsedBytes`](#parameter-monthlyusedbytes) | int | Monthly snapshot used bytes. | +| [`snapEnabled`](#parameter-snapenabled) | bool | Indicates whether the snapshot policy is enabled. | +| [`snapshotPolicyLocation`](#parameter-snapshotpolicylocation) | string | The location of the snapshot policy. | +| [`snapshotPolicyName`](#parameter-snapshotpolicyname) | string | The name of the snapshot policy. | +| [`weeklyDay`](#parameter-weeklyday) | string | The weekly snapshot day. | +| [`weeklyHour`](#parameter-weeklyhour) | int | The weekly snapshot hour. | +| [`weeklyMinute`](#parameter-weeklyminute) | int | The weekly snapshot minute. | +| [`weeklySnapshotsToKeep`](#parameter-weeklysnapshotstokeep) | int | Weekly snapshot count to keep. | +| [`weeklyUsedBytes`](#parameter-weeklyusedbytes) | int | Weekly snapshot used bytes. | + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `dailyHour` + +The daily snapshot hour. + +- Required: Yes +- Type: int + +### Parameter: `dailyMinute` + +The daily snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `dailySnapshotsToKeep` + +Daily snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `dailyUsedBytes` + +Daily snapshot used bytes. + +- Required: Yes +- Type: int + +### Parameter: `daysOfMonth` + +The monthly snapshot day. + +- Required: Yes +- Type: string + +### Parameter: `hourlyMinute` + +The hourly snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `hourlySnapshotsToKeep` + +Hourly snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `hourlyUsedBytes` + +Hourly snapshot used bytes. + +- Required: Yes +- Type: int + +### Parameter: `monthlyHour` + +The monthly snapshot hour. + +- Required: Yes +- Type: int + +### Parameter: `monthlyMinute` + +The monthly snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `monthlySnapshotsToKeep` + +Monthly snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `monthlyUsedBytes` + +Monthly snapshot used bytes. + +- Required: Yes +- Type: int + +### Parameter: `snapEnabled` + +Indicates whether the snapshot policy is enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `snapshotPolicyLocation` + +The location of the snapshot policy. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `snapshotPolicyName` + +The name of the snapshot policy. + +- Required: Yes +- Type: string + +### Parameter: `weeklyDay` + +The weekly snapshot day. + +- Required: Yes +- Type: string + +### Parameter: `weeklyHour` + +The weekly snapshot hour. + +- Required: Yes +- Type: int + +### Parameter: `weeklyMinute` + +The weekly snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `weeklySnapshotsToKeep` + +Weekly snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `weeklyUsedBytes` + +Weekly snapshot used bytes. + +- Required: Yes +- Type: int + +## 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/res/net-app/net-app-account/snapshot-policies/main.bicep b/avm/res/net-app/net-app-account/snapshot-policies/main.bicep new file mode 100644 index 0000000000..66eaca3163 --- /dev/null +++ b/avm/res/net-app/net-app-account/snapshot-policies/main.bicep @@ -0,0 +1,113 @@ +metadata name = 'Azure NetApp Files Snapshot Policy' +metadata description = 'This module deploys a Snapshot Policy for an Azure NetApp File.' +metadata owner = 'Azure/module-maintainers' + +@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 snapshotPolicyName string + +@description('Optional. The location of the snapshot policy.') +param snapshotPolicyLocation string = resourceGroup().location + +@description('Optional. The daily snapshot hour.') +param dailyHour int + +@description('Optional. The daily snapshot minute.') +param dailyMinute int + +@description('Optional. Daily snapshot count to keep.') +param dailySnapshotsToKeep int + +@description('Optional. Daily snapshot used bytes.') +param dailyUsedBytes int + +@description('Optional. The hourly snapshot minute.') +param hourlyMinute int + +@description('Optional. Hourly snapshot count to keep.') +param hourlySnapshotsToKeep int + +@description('Optional. Hourly snapshot used bytes.') +param hourlyUsedBytes int + +@description('Optional. The monthly snapshot day.') +param daysOfMonth string + +@description('Optional. The monthly snapshot hour.') +param monthlyHour int + +@description('Optional. The monthly snapshot minute.') +param monthlyMinute int + +@description('Optional. Monthly snapshot count to keep.') +param monthlySnapshotsToKeep int + +@description('Optional. Monthly snapshot used bytes.') +param monthlyUsedBytes int + +@description('Optional. The weekly snapshot day.') +param weeklyDay string + +@description('Optional. The weekly snapshot hour.') +param weeklyHour int + +@description('Optional. The weekly snapshot minute.') +param weeklyMinute int + +@description('Optional. Weekly snapshot count to keep.') +param weeklySnapshotsToKeep int + +@description('Optional. Weekly snapshot used bytes.') +param weeklyUsedBytes int + +@description('Optional. Indicates whether the snapshot policy is enabled.') +param snapEnabled bool = true + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-03-01' existing = { + name: netAppAccountName +} + +resource snapshotPolicies 'Microsoft.NetApp/netAppAccounts/snapshotPolicies@2024-03-01' = if (snapEnabled) { + name: snapshotPolicyName + parent: netAppAccount + location: snapshotPolicyLocation + properties: { + enabled: snapEnabled + dailySchedule: { + hour: dailyHour + minute: dailyMinute + snapshotsToKeep: dailySnapshotsToKeep + usedBytes: dailyUsedBytes + } + hourlySchedule: { + minute: hourlyMinute + snapshotsToKeep: hourlySnapshotsToKeep + usedBytes: hourlyUsedBytes + } + monthlySchedule: { + daysOfMonth: daysOfMonth + hour: monthlyHour + minute: monthlyMinute + snapshotsToKeep: monthlySnapshotsToKeep + usedBytes: monthlyUsedBytes + } + weeklySchedule: { + day: weeklyDay + hour: weeklyHour + minute: weeklyMinute + snapshotsToKeep: weeklySnapshotsToKeep + usedBytes: weeklyUsedBytes + } + } +} + +@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 diff --git a/avm/res/net-app/net-app-account/snapshot-policies/main.json b/avm/res/net-app/net-app-account/snapshot-policies/main.json new file mode 100644 index 0000000000..d92af406dd --- /dev/null +++ b/avm/res/net-app/net-app-account/snapshot-policies/main.json @@ -0,0 +1,204 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "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('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "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 From 59622847d81ef197322b5f57d21e5ce49d8f54eb Mon Sep 17 00:00:00 2001 From: Elena Batanero <46710322+elbatane@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:36:48 +0200 Subject: [PATCH 62/93] docs: ORPHANED Vnet Module (#3492) ## Description VNET module Orphaned ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.virtual-network](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=users%2Felbatane%2Fvnet_orphan)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [X] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Elena Batanero Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/network/virtual-network/ORPHANED.md | 4 ++++ avm/res/network/virtual-network/README.md | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 avm/res/network/virtual-network/ORPHANED.md diff --git a/avm/res/network/virtual-network/ORPHANED.md b/avm/res/network/virtual-network/ORPHANED.md new file mode 100644 index 0000000000..ef8fa911d2 --- /dev/null +++ b/avm/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/res/network/virtual-network/README.md b/avm/res/network/virtual-network/README.md index c61cf59589..02339df598 100644 --- a/avm/res/network/virtual-network/README.md +++ b/avm/res/network/virtual-network/README.md @@ -1,5 +1,10 @@ # 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 From dda478de2e74c32fc4eb9049de47edc60777f2d2 Mon Sep 17 00:00:00 2001 From: "Menghua Chen (MSFT)" <111940661+Menghua1@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:38:54 +0800 Subject: [PATCH 63/93] feat: Add new ptn modules `avm/ptn/azd/ml-project`. (#3244) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1228. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-project](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg)](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.ptn.azd.ml-project.yml | 88 + avm/ptn/azd/ml-project/README.md | 333 + avm/ptn/azd/ml-project/main.bicep | 174 + avm/ptn/azd/ml-project/main.json | 7436 +++++++++++++++++ .../tests/e2e/defaults/dependencies.bicep | 60 + .../tests/e2e/defaults/main.test.bicep | 61 + avm/ptn/azd/ml-project/version.json | 7 + 9 files changed, 8161 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.ml-project.yml create mode 100644 avm/ptn/azd/ml-project/README.md create mode 100644 avm/ptn/azd/ml-project/main.bicep create mode 100644 avm/ptn/azd/ml-project/main.json create mode 100644 avm/ptn/azd/ml-project/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/ml-project/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2167ffc054..73abc09b92 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,6 +16,7 @@ /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/ml-project/ @Azure/avm-ptn-azd-mlproject-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/monitoring/ @Azure/avm-ptn-azd-monitoring-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index a74c246995..719a8c2982 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -51,6 +51,7 @@ body: - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" + - "avm/ptn/azd/ml-project" - "avm/ptn/azd/ml-hub-dependencies" - "avm/ptn/azd/monitoring" - "avm/ptn/deployment-script/import-image-to-acr" diff --git a/.github/workflows/avm.ptn.azd.ml-project.yml b/.github/workflows/avm.ptn.azd.ml-project.yml new file mode 100644 index 0000000000..b2d2f60191 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.ml-project.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.ml-project" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.ml-project" + - "avm/ptn/azd/ml-project/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/ml-project" + workflowPath: ".github/workflows/avm.ptn.azd.ml-project.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit \ No newline at end of file diff --git a/avm/ptn/azd/ml-project/README.md b/avm/ptn/azd/ml-project/README.md new file mode 100644 index 0000000000..dc07753fe1 --- /dev/null +++ b/avm/ptn/azd/ml-project/README.md @@ -0,0 +1,333 @@ +# Azd Machine Learning workspace `[Azd/MlProject]` + +Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-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.MachineLearningServices/workspaces` | [2024-04-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01-preview/workspaces) | +| `Microsoft.MachineLearningServices/workspaces/computes` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2022-10-01/workspaces/computes) | +| `Microsoft.MachineLearningServices/workspaces/connections` | [2024-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01/workspaces/connections) | +| `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) | +| `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/ptn/azd/ml-project:`. + +- [Using only defaults](#example-1-using-only-defaults) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module mlProject 'br/public:avm/ptn/azd/ml-project:' = { + name: 'mlProjectDeployment' + params: { + // Required parameters + hubResourceId: '' + keyVaultName: '' + name: 'mlpmin001' + userAssignedName: 'mlpminuai001' + // 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 + "hubResourceId": { + "value": "" + }, + "keyVaultName": { + "value": "" + }, + "name": { + "value": "mlpmin001" + }, + "userAssignedName": { + "value": "mlpminuai001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-project:' + +// Required parameters +param hubResourceId = '' +param keyVaultName = '' +param name = 'mlpmin001' +param userAssignedName = 'mlpminuai001' +// Non-required parameters +param location = '' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hubResourceId`](#parameter-hubresourceid) | string | The resource ID of the AI Studio Hub Resource where this project should be created. | +| [`keyVaultName`](#parameter-keyvaultname) | string | The name of the key vault. | +| [`name`](#parameter-name) | string | The name of the machine learning workspace. | +| [`userAssignedName`](#parameter-userassignedname) | string | The name of the user assigned identity. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`hbiWorkspace`](#parameter-hbiworkspace) | bool | The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`projectKind`](#parameter-projectkind) | string | The type of Azure Machine Learning workspace to create. | +| [`projectManagedIdentities`](#parameter-projectmanagedidentities) | object | The managed identity definition for the machine learning resource. At least one identity type is required. | +| [`projectSku`](#parameter-projectsku) | string | Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. | +| [`roleDefinitionIdOrName`](#parameter-roledefinitionidorname) | array | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `hubResourceId` + +The resource ID of the AI Studio Hub Resource where this project should be created. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +The name of the key vault. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the machine learning workspace. + +- Required: Yes +- Type: string + +### Parameter: `userAssignedName` + +The 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: `hbiWorkspace` + +The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `projectKind` + +The type of Azure Machine Learning workspace to create. + +- Required: No +- Type: string +- Default: `'Project'` +- Allowed: + ```Bicep + [ + 'Default' + 'FeatureStore' + 'Hub' + 'Project' + ] + ``` + +### Parameter: `projectManagedIdentities` + +The managed identity definition for the machine learning resource. At least one identity type is required. + +- Required: No +- Type: object +- Default: + ```Bicep + { + systemAssigned: true + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-projectmanagedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided. | +| [`userAssignedResourceIds`](#parameter-projectmanagedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `projectManagedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided. + +- Required: No +- Type: bool + +### Parameter: `projectManagedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `projectSku` + +Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace. + +- Required: No +- Type: string +- Default: `'Basic'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Free' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `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'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' + 'f6c7c914-8db3-469d-8ca1-694a8f32e121' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + "key1": "value1" + "key2": "value2" + } + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `projectName` | string | The resource name of the machine learning workspace. | +| `projectPrincipalId` | string | The principal ID of the machine learning workspace. | +| `projectResourceId` | string | The resource ID of the machine learning workspace. | +| `resourceGroupName` | string | The resource group the machine learning workspace were deployed into. | + +## 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/key-vault/vault:0.9.0` | Remote reference | +| `br/public:avm/res/machine-learning-services/workspace:0.7.0` | Remote reference | +| `br/public:avm/res/managed-identity/user-assigned-identity: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/ptn/azd/ml-project/main.bicep b/avm/ptn/azd/ml-project/main.bicep new file mode 100644 index 0000000000..effc6771d5 --- /dev/null +++ b/avm/ptn/azd/ml-project/main.bicep @@ -0,0 +1,174 @@ +metadata name = 'Azd Machine Learning workspace' +metadata description = '''Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the machine learning workspace.') +param name string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +@description('Optional. Specifies the SKU, also referred as \'edition\' of the Azure Machine Learning workspace.') +@allowed([ + 'Free' + 'Basic' + 'Standard' + 'Premium' +]) +param projectSku string = 'Basic' + +@description('Optional. The type of Azure Machine Learning workspace to create.') +@allowed([ + 'Default' + 'Project' + 'Hub' + 'FeatureStore' +]) +param projectKind string = 'Project' + +@description('Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service.') +param hbiWorkspace bool = false + +@description('Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Required. The resource ID of the AI Studio Hub Resource where this project should be created.') +param hubResourceId string + +@description('Required. The name of the key vault.') +param keyVaultName string + +@description('Optional. The managed identity definition for the machine learning resource. At least one identity type is required.') +param projectManagedIdentities managedIdentitiesType = { + systemAssigned: true +} + +@description('Required. The name of the user assigned identity.') +param userAssignedName string + +@description('Optional. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader.') +param roleDefinitionIdOrName array = [ + 'f6c7c914-8db3-469d-8ca1-694a8f32e121' // AzureML Data Scientist + 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' // Azure Machine Learning Workspace Connection Secrets Reader +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-mlproject.${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 project 'br/public:avm/res/machine-learning-services/workspace:0.7.0' = { + name: '${uniqueString(deployment().name, location)}-project' + params: { + name: name + tags: tags + sku: projectSku + kind: projectKind + managedIdentities: projectManagedIdentities + hbiWorkspace: hbiWorkspace + publicNetworkAccess: publicNetworkAccess + hubResourceId: hubResourceId + enableTelemetry: enableTelemetry + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +module keyVaultAccess 'br/public:avm/res/key-vault/vault:0.9.0' = { + name: '${uniqueString(deployment().name, location)}-keyvault' + params: { + name: keyVault.name + accessPolicies: [ + { + objectId: project.outputs.systemAssignedMIPrincipalId + permissions: { secrets: [ 'get', 'list' ] } + } + ] + enableTelemetry: enableTelemetry + } +} + +module mlServiceRoleAssigned 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { + name: '${uniqueString(deployment().name, location)}-roleassignment' + params: { + name: userAssignedName + location: location + roleAssignments: [ + for id in roleDefinitionIdOrName: { + principalId: project.outputs.systemAssignedMIPrincipalId + roleDefinitionIdOrName: id + principalType: 'ServicePrincipal' + } + ] + enableTelemetry: enableTelemetry + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource group the machine learning workspace were deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the machine learning workspace.') +output projectResourceId string = project.outputs.resourceId + +@description('The resource name of the machine learning workspace.') +output projectName string = project.outputs.name + +@description('The principal ID of the machine learning workspace.') +output projectPrincipalId string = project.outputs.systemAssignedMIPrincipalId + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +} + diff --git a/avm/ptn/azd/ml-project/main.json b/avm/ptn/azd/ml-project/main.json new file mode 100644 index 0000000000..01d5610330 --- /dev/null +++ b/avm/ptn/azd/ml-project/main.json @@ -0,0 +1,7436 @@ +{ + "$schema": "https://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": "12979908494001456774" + }, + "name": "Azd Machine Learning workspace", + "description": "Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "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. Must be false if `primaryUserAssignedIdentity` is provided." + } + }, + "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 machine learning workspace." + } + }, + "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." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + }, + "projectSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Free", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace." + } + }, + "projectKind": { + "type": "string", + "defaultValue": "Project", + "allowedValues": [ + "Default", + "Project", + "Hub", + "FeatureStore" + ], + "metadata": { + "description": "Optional. The type of Azure Machine Learning workspace to create." + } + }, + "hbiWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled." + } + }, + "hubResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the AI Studio Hub Resource where this project should be created." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the key vault." + } + }, + "projectManagedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for the machine learning resource. At least one identity type is required." + } + }, + "userAssignedName": { + "type": "string", + "metadata": { + "description": "Required. The name of the user assigned identity." + } + }, + "roleDefinitionIdOrName": { + "type": "array", + "defaultValue": [ + "f6c7c914-8db3-469d-8ca1-694a8f32e121", + "ea01e6af-a1c1-4350-9563-ad00f8c72ec5" + ], + "metadata": { + "description": "Optional. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-mlproject.{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": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "project": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-project', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "sku": { + "value": "[parameters('projectSku')]" + }, + "kind": { + "value": "[parameters('projectKind')]" + }, + "managedIdentities": { + "value": "[parameters('projectManagedIdentities')]" + }, + "hbiWorkspace": { + "value": "[parameters('hbiWorkspace')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "hubResourceId": { + "value": "[parameters('hubResourceId')]" + }, + "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.29.47.4906", + "templateHash": "8914196510655371542" + }, + "name": "Machine Learning Services Workspaces", + "description": "This module deploys a Machine Learning Services 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. Must be false if `primaryUserAssignedIdentity` is provided." + } + }, + "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 + }, + "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": "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 + }, + "featureStoreSettingType": { + "type": "object", + "properties": { + "computeRuntime": { + "type": "object", + "properties": { + "sparkRuntimeVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The spark runtime version." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Compute runtime config for feature store type workspace." + } + }, + "offlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The offline store connection name." + } + }, + "onlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The online store connection name." + } + } + }, + "nullable": true + }, + "OutboundRuleType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "FQDN": { + "$ref": "#/definitions/FqdnOutboundRuleType" + }, + "PrivateEndpoint": { + "$ref": "#/definitions/PrivateEndpointOutboundRule" + }, + "ServiceTag": { + "$ref": "#/definitions/ServiceTagOutboundRule" + } + } + } + }, + "FqdnOutboundRuleType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "FQDN" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "string", + "metadata": { + "description": "Required. Fully Qualified Domain Name to allow for outbound traffic." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "PrivateEndpointOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "PrivateEndpoint" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound' or 'AllowInternetOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "serviceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target resource for the private endpoint." + } + }, + "sparkEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the private endpoint can be used by jobs running on Spark." + } + }, + "subresourceTarget": { + "type": "string", + "metadata": { + "description": "Required. The sub resource to connect for the private endpoint." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "ServiceTagOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "ServiceTag" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "portRanges": { + "type": "string", + "metadata": { + "description": "Required. The name of the service tag to allow." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. The protocol to allow. Provide an asterisk(*) to allow any protocol." + } + }, + "serviceTag": { + "type": "string", + "metadata": { + "description": "Required. Which ports will be allow traffic by this rule. Provide an asterisk(*) to allow any port." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "managedNetworkSettingType": { + "type": "object", + "properties": { + "isolationMode": { + "type": "string", + "allowedValues": [ + "AllowInternetOutbound", + "AllowOnlyApprovedOutbound", + "Disabled" + ], + "metadata": { + "description": "Required. Isolation mode for the managed network of a machine learning workspace." + } + }, + "outboundRules": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/OutboundRuleType", + "metadata": { + "description": "Required. The outbound rule. The name of the rule is the object key." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Outbound rules for the managed network of a machine learning workspace." + } + } + }, + "nullable": true + }, + "serverlessComputeSettingType": { + "type": "object", + "properties": { + "serverlessComputeCustomSubnet": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of an existing virtual network subnet in which serverless compute nodes should be deployed." + } + }, + "serverlessComputeNoPublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The flag to signal if serverless compute nodes deployed in custom vNet would have no public IP addresses for a workspace with private endpoint." + } + } + }, + "nullable": true + }, + "workspaceHubConfigType": { + "type": "object", + "properties": { + "additionalWorkspaceStorageAccounts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of additional storage accounts to attach to the workspace." + } + }, + "defaultWorkspaceResourceGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default resource group for projects created in the workspace hub." + } + } + }, + "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 + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "connectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + } + }, + "_1.aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/_1.aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/_1.accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/_1.apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/_1.customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/_1.noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/_1.oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/_1.patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/_1.sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the machine learning workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "sku": { + "type": "string", + "allowedValues": [ + "Free", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Required. Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Project", + "Hub", + "FeatureStore" + ], + "metadata": { + "description": "Optional. The type of Azure Machine Learning workspace to create." + } + }, + "associatedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Storage Account. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedKeyVaultResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Key Vault. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedApplicationInsightsResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Application Insights. Required if 'kind' is 'Default' or 'FeatureStore'." + } + }, + "associatedContainerRegistryResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the associated Container Registry." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "hbiWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service." + } + }, + "hubResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the hub to associate with the workspace. Required if 'kind' is set to 'Project'." + } + }, + "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." + } + }, + "computes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Computes to create respectively attach to the workspace." + } + }, + "connections": { + "type": "array", + "items": { + "$ref": "#/definitions/connectionType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Connections to create in the workspace." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." + } + }, + "featureStoreSettings": { + "$ref": "#/definitions/featureStoreSettingType", + "metadata": { + "description": "Conditional. Settings for feature store type workspaces. Required if 'kind' is set to 'FeatureStore'." + } + }, + "managedNetworkSettings": { + "$ref": "#/definitions/managedNetworkSettingType", + "metadata": { + "description": "Optional. Managed Network settings for a machine learning workspace." + } + }, + "serverlessComputeSettings": { + "$ref": "#/definitions/serverlessComputeSettingType", + "metadata": { + "description": "Optional. Settings for serverless compute created in the workspace." + } + }, + "systemDatastoresAuthMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "accessKey", + "identity" + ], + "metadata": { + "description": "Optional. The authentication mode used by the workspace when connecting to the default storage account." + } + }, + "workspaceHubConfig": { + "$ref": "#/definitions/workspaceHubConfigType", + "metadata": { + "description": "Optional. Configuration for workspace hub settings." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this workspace." + } + }, + "discoveryUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. URL for the discovery service to identify regional endpoints for machine learning experimentation services." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "imageBuildCompute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The compute name for image build." + } + }, + "primaryUserAssignedIdentity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The user assigned identity resource ID that represents the workspace identity. Required if 'userAssignedIdentities' is not empty and may not be used if 'systemAssignedIdentity' is enabled." + } + }, + "serviceManagedResourcesSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The service managed resource settings." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of shared private link resources in this workspace. Note: This property is not idempotent." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled." + } + } + }, + "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": { + "AzureML Compute Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e503ece1-11d0-4e8e-8e2c-7a6c3bf38815')]", + "AzureML Data Scientist": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f6c7c914-8db3-469d-8ca1-694a8f32e121')]", + "AzureML Metrics Writer (preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '635dd51f-9968-44d3-b7fb-6d9a6bd613ae')]", + "AzureML Registry User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1823dd4f-9b8c-4ab6-ab4e-7397a3684615')]", + "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')]" + } + }, + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.machinelearningservices-workspace.{0}.{1}', replace('0.7.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" + } + } + } + } + }, + "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'), '/'))]" + }, + "workspace": { + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2024-04-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]", + "tier": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": "[union(createObject('friendlyName', parameters('name'), 'storageAccount', parameters('associatedStorageAccountResourceId'), 'keyVault', parameters('associatedKeyVaultResourceId'), 'applicationInsights', parameters('associatedApplicationInsightsResourceId'), 'containerRegistry', parameters('associatedContainerRegistryResourceId'), 'hbiWorkspace', parameters('hbiWorkspace'), 'description', parameters('description'), 'discoveryUrl', parameters('discoveryUrl'), 'encryption', if(not(empty(parameters('customerManagedKey'))), createObject('status', 'Enabled', '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('keyVaultArmId', 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'), '/'))), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null()), 'imageBuildCompute', parameters('imageBuildCompute'), 'primaryUserAssignedIdentity', parameters('primaryUserAssignedIdentity'), 'systemDatastoresAuthMode', parameters('systemDatastoresAuthMode'), 'publicNetworkAccess', parameters('publicNetworkAccess'), 'serviceManagedResourcesSettings', parameters('serviceManagedResourcesSettings'), 'featureStoreSettings', parameters('featureStoreSettings'), 'hubResourceId', parameters('hubResourceId'), 'managedNetwork', parameters('managedNetworkSettings'), 'serverlessComputeSettings', parameters('serverlessComputeSettings'), 'workspaceHubConfig', parameters('workspaceHubConfig')), if(not(empty(parameters('sharedPrivateLinkResources'))), createObject('sharedPrivateLinkResources', parameters('sharedPrivateLinkResources')), createObject()))]", + "kind": "[parameters('kind')]", + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "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.MachineLearningServices/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_diagnosticSettings": { + "copy": { + "name": "workspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.MachineLearningServices/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": "[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": [ + "workspace" + ] + }, + "workspace_roleAssignments": { + "copy": { + "name": "workspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.MachineLearningServices/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.MachineLearningServices/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_computes": { + "copy": { + "name": "workspace_computes", + "count": "[length(coalesce(parameters('computes'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-compute', parameters('name'), coalesce(parameters('computes'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].location]" + }, + "sku": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'sku')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'tags')]" + }, + "deployCompute": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'deployCompute')]" + }, + "computeLocation": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'computeLocation')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'description')]" + }, + "disableLocalAuth": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'disableLocalAuth')]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'resourceId')]" + }, + "computeType": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].computeType]" + }, + "properties": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'properties')]" + } + }, + "template": { + "$schema": "https://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": "8580750401363518569" + }, + "name": "Machine Learning Services Workspaces Computes", + "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", + "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": { + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 16, + "metadata": { + "description": "Required. Name of the compute." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Specifies the location of the resource." + } + }, + "sku": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Basic", + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Specifies the sku, also referred as \"edition\". Required for creating a compute resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Contains resource tags defined as key-value pairs. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "deployCompute": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to specify whether to deploy the compute. Required only for attach (i.e. providing a resource ID), as in this case the operation is not idempotent, i.e. a second deployment will fail. Therefore, this flag needs to be set to \"false\" as long as the compute resource exists." + } + }, + "computeLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for the underlying compute. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the Machine Learning compute." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure customers can use only MSI and AAD exclusively for authentication." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ARM resource ID of the underlying compute." + } + }, + "computeType": { + "type": "string", + "allowedValues": [ + "AKS", + "AmlCompute", + "ComputeInstance", + "Databricks", + "DataFactory", + "DataLakeAnalytics", + "HDInsight", + "Kubernetes", + "SynapseSpark", + "VirtualMachine" + ], + "metadata": { + "description": "Required. Set the object type." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the compute. Will be ignored in case \"resourceId\" is set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + } + }, + "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())]" + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "compute": { + "condition": "[equals(parameters('deployCompute'), true())]", + "type": "Microsoft.MachineLearningServices/workspaces/computes", + "apiVersion": "2022-10-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[if(empty(parameters('resourceId')), parameters('tags'), null())]", + "sku": "[if(empty(parameters('resourceId')), createObject('name', parameters('sku'), 'tier', parameters('sku')), null())]", + "identity": "[if(empty(parameters('resourceId')), variables('identity'), null())]", + "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the compute." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the compute." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the compute was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('compute', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('compute', '2022-10-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "workspace", + "workspace_privateEndpoints" + ] + }, + "workspace_connections": { + "copy": { + "name": "workspace_connections", + "count": "[length(parameters('connections'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-connection', parameters('name'), parameters('connections')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('connections')[copyIndex()].name]" + }, + "category": { + "value": "[parameters('connections')[copyIndex()].category]" + }, + "expiryTime": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'expiryTime')]" + }, + "isSharedToAll": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'isSharedToAll')]" + }, + "metadata": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'metadata')]" + }, + "sharedUserList": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'sharedUserList')]" + }, + "target": { + "value": "[parameters('connections')[copyIndex()].target]" + }, + "value": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'value')]" + }, + "connectionProperties": { + "value": "[parameters('connections')[copyIndex()].connectionProperties]" + } + }, + "template": { + "$schema": "https://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": "2277907099827503661" + }, + "name": "Machine Learning Services Workspaces Connections", + "description": "This module creates a connection in a Machine Learning Services workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "metadataType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_export!": true + } + }, + "aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "accountKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccountKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccountKey", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + } + }, + "workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + } + }, + "workspaceConnectionAccountKey": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection key." + } + } + } + }, + "workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + } + }, + "workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + } + }, + "workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + } + }, + "workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + } + }, + "workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + } + }, + "workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + } + }, + "workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "$ref": "#/definitions/metadataType", + "defaultValue": {}, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "connection": { + "type": "Microsoft.MachineLearningServices/workspaces/connections", + "apiVersion": "2024-04-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "properties": "[union(createObject('category', parameters('category'), 'expiryTime', parameters('expiryTime'), 'isSharedToAll', parameters('isSharedToAll'), 'metadata', parameters('metadata'), 'sharedUserList', parameters('sharedUserList'), 'target', parameters('target'), 'value', parameters('value')), parameters('connectionProperties'))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the connection." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/connections', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the connection." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the connection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), 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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')))))), 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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')), '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": "3308873178893851812" + }, + "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.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" + } + } + } + } + }, + "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]" + }, + "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 machine learning service." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the machine learning service was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the machine learning service." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('workspace', '2024-04-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('workspace', '2024-04-01-preview', 'full').location]" + } + } + } + } + }, + "keyVaultAccess": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "accessPolicies": { + "value": [ + { + "objectId": "[reference('project').outputs.systemAssignedMIPrincipalId.value]", + "permissions": { + "secrets": [ + "get", + "list" + ] + } + } + ] + }, + "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.29.47.4906", + "templateHash": "10085839006881327962" + }, + "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": { + "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": "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": "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('0.9.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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "7494731697751039419" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "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.29.47.4906", + "templateHash": "114626909766354577" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "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 + } + }, + "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": { + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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'))]" + }, + "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.29.47.4906", + "templateHash": "14269695922191217406" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "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 + } + }, + "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": { + "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": { + "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())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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": { + "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], '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": [ + "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", + "metadata": { + "description": "The private endpoints of the key vault." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(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": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } + } + }, + "dependsOn": [ + "keyVault", + "project" + ] + }, + "mlServiceRoleAssigned": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-roleassignment', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('userAssignedName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "roleAssignments": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('roleDefinitionIdOrName'))]", + "input": "[createObject('principalId', reference('project').outputs.systemAssignedMIPrincipalId.value, 'roleDefinitionIdOrName', parameters('roleDefinitionIdOrName')[copyIndex('value')], 'principalType', 'ServicePrincipal')]" + } + ] + }, + "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.29.47.4906", + "templateHash": "10609859695208799167" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity.", + "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 + }, + "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('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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "3716898257490923786" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential.", + "owner": "Azure/module-maintainers" + }, + "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]" + } + } + } + }, + "dependsOn": [ + "project" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the machine learning workspace were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "projectResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the machine learning workspace." + }, + "value": "[reference('project').outputs.resourceId.value]" + }, + "projectName": { + "type": "string", + "metadata": { + "description": "The resource name of the machine learning workspace." + }, + "value": "[reference('project').outputs.name.value]" + }, + "projectPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the machine learning workspace." + }, + "value": "[reference('project').outputs.systemAssignedMIPrincipalId.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/ml-project/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/ml-project/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..8936dfcb78 --- /dev/null +++ b/avm/ptn/azd/ml-project/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 AI Studio Hub Resource to create.') +param hubName 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('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +module storageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: '${uniqueString(deployment().name, location)}-storage' + params: { + name: storageAccountName + tags: tags + location: location + } +} + +module keyvault 'br/public:avm/res/key-vault/vault:0.9.0' = { + name: '${uniqueString(deployment().name, location)}-keyvault' + params: { + enablePurgeProtection: false + location: location + name: keyVaultName + } +} + +module hub 'br/public:avm/res/machine-learning-services/workspace:0.7.0' = { + name: '${uniqueString(deployment().name, location)}-hub' + params: { + name: hubName + tags: tags + location: location + sku: 'Basic' + kind: 'Hub' + associatedKeyVaultResourceId: keyvault.outputs.resourceId + associatedStorageAccountResourceId: storageAccount.outputs.resourceId + } +} + +@description('The resource ID of the AI Studio Hub Resource.') +output hubResourceId string = hub.outputs.resourceId + +@description('The name of the key vault.') +output keyVaultName string = keyvault.outputs.name + diff --git a/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..996d63a5bd --- /dev/null +++ b/avm/ptn/azd/ml-project/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}-azd-ml-project-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'mlpmin' + +@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 dependencies 'dependencies.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-dependencies' + scope: resourceGroup + params: { + hubName: '${namePrefix}${serviceShort}hub001' + keyVaultName: '${namePrefix}${serviceShort}kv001' + storageAccountName: '${namePrefix}${serviceShort}sa001' + } +} + +// ============== // +// 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 + keyVaultName: dependencies.outputs.keyVaultName + userAssignedName: '${namePrefix}${serviceShort}uai001' + hubResourceId: dependencies.outputs.hubResourceId + } + } +] diff --git a/avm/ptn/azd/ml-project/version.json b/avm/ptn/azd/ml-project/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/ml-project/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From a49727224d91a95597b7108cf0a4a589af6f023a Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:46:57 +0200 Subject: [PATCH 64/93] fix: cognitive services readme update (#3508) ## Description Fix readme regen Add small change to trigger publishing ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Feriqua%2Fcognitive-readme)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/cognitive-services/account/README.md | 8 ++++---- avm/res/cognitive-services/account/main.bicep | 2 +- avm/res/cognitive-services/account/main.json | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index fb852b55a3..9462bf4a9b 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1614,7 +1614,7 @@ param tags = { | Parameter | Type | Description | | :-- | :-- | :-- | -| [`kind`](#parameter-kind) | string | Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | +| [`kind`](#parameter-kind) | string | Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | | [`name`](#parameter-name) | string | The name of Cognitive Services account. | **Conditional parameters** @@ -1638,7 +1638,7 @@ param tags = { | [`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. | -| [`migrationToken`](#parameter-migrationtoken) | string | Resource migration token. | +| [`migrationToken`](#parameter-migrationtoken) | securestring | Resource migration token. | | [`networkAcls`](#parameter-networkacls) | object | A collection of rules governing the accessibility 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. | @@ -1652,7 +1652,7 @@ param tags = { ### Parameter: `kind` -Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. +Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. - Required: Yes - Type: string @@ -2114,7 +2114,7 @@ The resource ID(s) to assign to the resource. Required if a user assigned identi Resource migration token. - Required: No -- Type: string +- Type: securestring ### Parameter: `networkAcls` diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index d7c788c144..96147cc72d 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -5,7 +5,7 @@ metadata owner = 'Azure/module-maintainers' @description('Required. The name of Cognitive Services account.') param name string -@description('Required. Kind of the Cognitive Services. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@description('Required. Kind of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') @allowed([ 'AIServices' 'AnomalyDetector' diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 7f45a5e8dc..013a5b598c 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "325704537018634474" + "templateHash": "9722036366573656954" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -668,7 +668,7 @@ "TextTranslation" ], "metadata": { - "description": "Required. Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." } }, "sku": { From a14856cbfc1e22c4a2bd5acde7f354189203b103 Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:48:51 +0200 Subject: [PATCH 65/93] fix: Trigger azd ml project publishing (#3511) ## Description fix issue template order add small change to trigger publishing ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-project](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg?branch=users%2Feriqua%2Fissue-temp)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- .github/ISSUE_TEMPLATE/avm_module_issue.yml | 2 +- avm/ptn/azd/ml-project/README.md | 4 ++-- avm/ptn/azd/ml-project/main.bicep | 5 ++--- avm/ptn/azd/ml-project/main.json | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 719a8c2982..1c5486a04e 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -51,8 +51,8 @@ body: - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - - "avm/ptn/azd/ml-project" - "avm/ptn/azd/ml-hub-dependencies" + - "avm/ptn/azd/ml-project" - "avm/ptn/azd/monitoring" - "avm/ptn/deployment-script/import-image-to-acr" - "avm/ptn/dev-ops/cicd-agents-and-runners" diff --git a/avm/ptn/azd/ml-project/README.md b/avm/ptn/azd/ml-project/README.md index dc07753fe1..adc6341c6e 100644 --- a/avm/ptn/azd/ml-project/README.md +++ b/avm/ptn/azd/ml-project/README.md @@ -142,7 +142,7 @@ param location = '' | [`projectKind`](#parameter-projectkind) | string | The type of Azure Machine Learning workspace to create. | | [`projectManagedIdentities`](#parameter-projectmanagedidentities) | object | The managed identity definition for the machine learning resource. At least one identity type is required. | | [`projectSku`](#parameter-projectsku) | string | Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace. | -| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled. | | [`roleDefinitionIdOrName`](#parameter-roledefinitionidorname) | array | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -268,7 +268,7 @@ Specifies the SKU, also referred as 'edition' of the Azure Machine Learning work ### Parameter: `publicNetworkAccess` -Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. +Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled. - Required: No - Type: string diff --git a/avm/ptn/azd/ml-project/main.bicep b/avm/ptn/azd/ml-project/main.bicep index effc6771d5..96179ddb4b 100644 --- a/avm/ptn/azd/ml-project/main.bicep +++ b/avm/ptn/azd/ml-project/main.bicep @@ -45,7 +45,7 @@ param projectKind string = 'Project' @description('Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service.') param hbiWorkspace bool = false -@description('Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled.') +@description('Optional. Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled.') @allowed([ 'Enabled' 'Disabled' @@ -121,7 +121,7 @@ module keyVaultAccess 'br/public:avm/res/key-vault/vault:0.9.0' = { accessPolicies: [ { objectId: project.outputs.systemAssignedMIPrincipalId - permissions: { secrets: [ 'get', 'list' ] } + permissions: { secrets: ['get', 'list'] } } ] enableTelemetry: enableTelemetry @@ -171,4 +171,3 @@ type managedIdentitiesType = { @description('Optional. The resource ID(s) to assign to the resource.') userAssignedResourceIds: string[]? } - diff --git a/avm/ptn/azd/ml-project/main.json b/avm/ptn/azd/ml-project/main.json index 01d5610330..f130a38a14 100644 --- a/avm/ptn/azd/ml-project/main.json +++ b/avm/ptn/azd/ml-project/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "12979908494001456774" + "templateHash": "15406074241490987266" }, "name": "Azd Machine Learning workspace", "description": "Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -106,7 +106,7 @@ "Disabled" ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled." + "description": "Optional. Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled." } }, "hubResourceId": { From 1de95a621a74c12f51225bec1f7cae0bb32f138c Mon Sep 17 00:00:00 2001 From: "Jinlong Shi (MSFT)" <139106314+jerryshia@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:50:47 +0800 Subject: [PATCH 66/93] feat: Add new ptn modules `avm/ptn/azd/aks`. (#3250) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1224. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.aks](https://github.com/jerryshia/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml/badge.svg?branch=azd%2Faks)](https://github.com/jerryshia/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: Alexander Sehr --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.ptn.azd.aks.yml | 88 + avm/ptn/azd/aks/README.md | 1045 ++ avm/ptn/azd/aks/main.bicep | 466 + avm/ptn/azd/aks/main.json | 9163 +++++++++++++++++ .../aks/tests/e2e/defaults/dependencies.bicep | 56 + .../aks/tests/e2e/defaults/main.test.bicep | 63 + .../azd/aks/tests/e2e/max/dependencies.bicep | 56 + avm/ptn/azd/aks/tests/e2e/max/main.test.bicep | 87 + avm/ptn/azd/aks/version.json | 7 + 11 files changed, 11033 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.aks.yml create mode 100644 avm/ptn/azd/aks/README.md create mode 100644 avm/ptn/azd/aks/main.bicep create mode 100644 avm/ptn/azd/aks/main.json create mode 100644 avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep create mode 100644 avm/ptn/azd/aks/tests/e2e/max/main.test.bicep create mode 100644 avm/ptn/azd/aks/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 73abc09b92..f5002e3373 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,6 +13,7 @@ #/avm/ptn/avd-lza/networking/ @Azure/avm-ptn-avd-lza-networking-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/session-hosts/ @Azure/avm-ptn-avd-lza-sessionhosts-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/acr-container-app/ @Azure/avm-ptn-azd-acrcontainerapp-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/aks/ @Azure/avm-ptn-azd-aks-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 1c5486a04e..2d27f5792e 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -48,6 +48,7 @@ body: # - "avm/ptn/avd-lza/networking" # - "avm/ptn/avd-lza/session-hosts" - "avm/ptn/azd/acr-container-app" + - "avm/ptn/azd/aks" - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" diff --git a/.github/workflows/avm.ptn.azd.aks.yml b/.github/workflows/avm.ptn.azd.aks.yml new file mode 100644 index 0000000000..8197fd7c84 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.aks.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.aks" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.aks.yml" + - "avm/ptn/azd/aks/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/aks" + workflowPath: ".github/workflows/avm.ptn.azd.aks.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/azd/aks/README.md b/avm/ptn/azd/aks/README.md new file mode 100644 index 0000000000..18098d7a71 --- /dev/null +++ b/avm/ptn/azd/aks/README.md @@ -0,0 +1,1045 @@ +# Azd AKS `[Azd/Aks]` + +Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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.ContainerRegistry/registries` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries) | +| `Microsoft.ContainerRegistry/registries/cacheRules` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/cacheRules) | +| `Microsoft.ContainerRegistry/registries/credentialSets` | [2023-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/credentialSets) | +| `Microsoft.ContainerRegistry/registries/replications` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/replications) | +| `Microsoft.ContainerRegistry/registries/scopeMaps` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/scopeMaps) | +| `Microsoft.ContainerRegistry/registries/webhooks` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/webhooks) | +| `Microsoft.ContainerService/managedClusters` | [2024-03-02-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerService/2024-03-02-preview/managedClusters) | +| `Microsoft.ContainerService/managedClusters/agentPools` | [2023-07-02-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerService/2023-07-02-preview/managedClusters/agentPools) | +| `Microsoft.ContainerService/managedClusters/maintenanceConfigurations` | [2023-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerService/2023-10-01/managedClusters/maintenanceConfigurations) | +| `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` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-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.KubernetesConfiguration/extensions` | [2022-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KubernetesConfiguration/2022-03-01/extensions) | +| `Microsoft.KubernetesConfiguration/fluxConfigurations` | [2022-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KubernetesConfiguration/2022-03-01/fluxConfigurations) | +| `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-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/ptn/azd/aks:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module aks 'br/public:avm/ptn/azd/aks:' = { + name: 'aksDeployment' + params: { + // Required parameters + containerRegistryName: '' + keyVaultName: '' + logAnalyticsName: '' + name: '' + principalId: '' + // 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 + "containerRegistryName": { + "value": "" + }, + "keyVaultName": { + "value": "" + }, + "logAnalyticsName": { + "value": "" + }, + "name": { + "value": "" + }, + "principalId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/aks:' + +// Required parameters +param containerRegistryName = '' +param keyVaultName = '' +param logAnalyticsName = '' +param name = '' +param principalId = '' +// 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 aks 'br/public:avm/ptn/azd/aks:' = { + name: 'aksDeployment' + params: { + // Required parameters + containerRegistryName: '' + keyVaultName: '' + logAnalyticsName: '' + name: '' + principalId: '' + // Non-required parameters + acrSku: 'Basic' + agentPools: [ + { + maxPods: 30 + maxSurge: '33%' + mode: 'User' + name: 'npuserpool' + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'standard_a2' + } + ] + aksClusterRoleAssignmentName: '' + containerRegistryRoleName: '' + dnsPrefix: 'dep-dns-paamax' + location: '' + principalType: 'ServicePrincipal' + skuTier: 'Free' + webApplicationRoutingEnabled: 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 + "containerRegistryName": { + "value": "" + }, + "keyVaultName": { + "value": "" + }, + "logAnalyticsName": { + "value": "" + }, + "name": { + "value": "" + }, + "principalId": { + "value": "" + }, + // Non-required parameters + "acrSku": { + "value": "Basic" + }, + "agentPools": { + "value": [ + { + "maxPods": 30, + "maxSurge": "33%", + "mode": "User", + "name": "npuserpool", + "osType": "Linux", + "type": "VirtualMachineScaleSets", + "vmSize": "standard_a2" + } + ] + }, + "aksClusterRoleAssignmentName": { + "value": "" + }, + "containerRegistryRoleName": { + "value": "" + }, + "dnsPrefix": { + "value": "dep-dns-paamax" + }, + "location": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "skuTier": { + "value": "Free" + }, + "webApplicationRoutingEnabled": { + "value": true + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/aks:' + +// Required parameters +param containerRegistryName = '' +param keyVaultName = '' +param logAnalyticsName = '' +param name = '' +param principalId = '' +// Non-required parameters +param acrSku = 'Basic' +param agentPools = [ + { + maxPods: 30 + maxSurge: '33%' + mode: 'User' + name: 'npuserpool' + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'standard_a2' + } +] +param aksClusterRoleAssignmentName = '' +param containerRegistryRoleName = '' +param dnsPrefix = 'dep-dns-paamax' +param location = '' +param principalType = 'ServicePrincipal' +param skuTier = 'Free' +param webApplicationRoutingEnabled = true +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerRegistryName`](#parameter-containerregistryname) | string | Name of your Azure Container Registry. | +| [`keyVaultName`](#parameter-keyvaultname) | string | Name of the Key Vault. Must be globally unique. | +| [`logAnalyticsName`](#parameter-loganalyticsname) | string | The name of the connected log analytics workspace. | +| [`name`](#parameter-name) | string | The name of the parent managed cluster. Required if the template is used in a standalone deployment. | +| [`principalId`](#parameter-principalid) | string | Id of the user or app to assign application roles. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appGatewayResourceId`](#parameter-appgatewayresourceid) | string | Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aadProfileEnableAzureRBAC`](#parameter-aadprofileenableazurerbac) | bool | Specifies whether to enable Azure RBAC for Kubernetes authorization. | +| [`acrSku`](#parameter-acrsku) | string | Tier of your Azure container registry. | +| [`agentPools`](#parameter-agentpools) | array | Define one or more secondary/additional agent pools. | +| [`aksClusterRoleAssignmentName`](#parameter-aksclusterroleassignmentname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`containerRegistryRoleName`](#parameter-containerregistryrolename) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`dnsPrefix`](#parameter-dnsprefix) | string | Specifies the DNS prefix specified when creating the managed cluster. | +| [`dnsServiceIP`](#parameter-dnsserviceip) | string | Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`kubernetesVersion`](#parameter-kubernetesversion) | string | Kubernetes Version. | +| [`location`](#parameter-location) | string | Specifies the location of AKS cluster. It picks up Resource Group's location by default. | +| [`monitoringWorkspaceResourceId`](#parameter-monitoringworkspaceresourceid) | string | Resource ID of the monitoring log analytics workspace. | +| [`networkDataplane`](#parameter-networkdataplane) | string | Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin. | +| [`networkPlugin`](#parameter-networkplugin) | string | Network plugin used for building the Kubernetes network. | +| [`networkPluginMode`](#parameter-networkpluginmode) | string | Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin. | +| [`networkPolicy`](#parameter-networkpolicy) | string | Specifies the network policy used for building Kubernetes network. - calico or azure. | +| [`nodeResourceGroupName`](#parameter-noderesourcegroupname) | string | The name of the resource group for the managed resources of the AKS cluster. | +| [`podCidr`](#parameter-podcidr) | string | Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used. | +| [`principalType`](#parameter-principaltype) | string | The type of principal to assign application roles. | +| [`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 networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'. | +| [`scopeMaps`](#parameter-scopemaps) | array | Scope maps setting. | +| [`serviceCidr`](#parameter-servicecidr) | string | A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges. | +| [`skuTier`](#parameter-skutier) | string | Tier of a managed cluster SKU. | +| [`sshPublicKey`](#parameter-sshpublickey) | string | Specifies the SSH RSA public key string for the Linux nodes. | +| [`tags`](#parameter-tags) | object | Custom tags to apply to the AKS resources. | +| [`webApplicationRoutingEnabled`](#parameter-webapplicationroutingenabled) | bool | Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. | + +### Parameter: `containerRegistryName` + +Name of your Azure Container Registry. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +Name of the Key Vault. Must be globally unique. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsName` + +The name of the connected log analytics workspace. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the parent managed cluster. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `principalId` + +Id of the user or app to assign application roles. + +- Required: Yes +- Type: string + +### Parameter: `appGatewayResourceId` + +Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`. + +- Required: No +- Type: string + +### Parameter: `aadProfileEnableAzureRBAC` + +Specifies whether to enable Azure RBAC for Kubernetes authorization. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `acrSku` + +Tier of your Azure container registry. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `agentPools` + +Define one or more secondary/additional agent pools. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-agentpoolsname) | string | The name of the agent pool. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`availabilityZones`](#parameter-agentpoolsavailabilityzones) | array | The availability zones of the agent pool. | +| [`count`](#parameter-agentpoolscount) | int | The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`enableAutoScaling`](#parameter-agentpoolsenableautoscaling) | bool | Whether to enable auto-scaling for the agent pool. | +| [`enableDefaultTelemetry`](#parameter-agentpoolsenabledefaulttelemetry) | bool | The enable default telemetry of the agent pool. | +| [`enableEncryptionAtHost`](#parameter-agentpoolsenableencryptionathost) | bool | Whether to enable encryption at host for the agent pool. | +| [`enableFIPS`](#parameter-agentpoolsenablefips) | bool | Whether to enable FIPS for the agent pool. | +| [`enableNodePublicIP`](#parameter-agentpoolsenablenodepublicip) | bool | Whether to enable node public IP for the agent pool. | +| [`enableUltraSSD`](#parameter-agentpoolsenableultrassd) | bool | Whether to enable Ultra SSD for the agent pool. | +| [`gpuInstanceProfile`](#parameter-agentpoolsgpuinstanceprofile) | string | The GPU instance profile of the agent pool. | +| [`kubeletDiskType`](#parameter-agentpoolskubeletdisktype) | string | The kubelet disk type of the agent pool. | +| [`maxCount`](#parameter-agentpoolsmaxcount) | int | The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`maxPods`](#parameter-agentpoolsmaxpods) | int | The maximum number of pods that can run on a node. | +| [`maxSurge`](#parameter-agentpoolsmaxsurge) | string | The maximum number of nodes that can be created during an upgrade. | +| [`minCount`](#parameter-agentpoolsmincount) | int | The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`minPods`](#parameter-agentpoolsminpods) | int | The minimum number of pods that can run on a node. | +| [`mode`](#parameter-agentpoolsmode) | string | The mode of the agent pool. | +| [`nodeLabels`](#parameter-agentpoolsnodelabels) | object | The node labels of the agent pool. | +| [`nodePublicIpPrefixId`](#parameter-agentpoolsnodepublicipprefixid) | string | The node public IP prefix ID of the agent pool. | +| [`nodeTaints`](#parameter-agentpoolsnodetaints) | array | The node taints of the agent pool. | +| [`orchestratorVersion`](#parameter-agentpoolsorchestratorversion) | string | The Kubernetes version of the agent pool. | +| [`osDiskSizeGB`](#parameter-agentpoolsosdisksizegb) | int | The OS disk size in GB of the agent pool. | +| [`osDiskType`](#parameter-agentpoolsosdisktype) | string | The OS disk type of the agent pool. | +| [`osSku`](#parameter-agentpoolsossku) | string | The OS SKU of the agent pool. | +| [`osType`](#parameter-agentpoolsostype) | string | The OS type of the agent pool. | +| [`podSubnetId`](#parameter-agentpoolspodsubnetid) | string | The pod subnet ID of the agent pool. | +| [`proximityPlacementGroupResourceId`](#parameter-agentpoolsproximityplacementgroupresourceid) | string | The proximity placement group resource ID of the agent pool. | +| [`scaleDownMode`](#parameter-agentpoolsscaledownmode) | string | The scale down mode of the agent pool. | +| [`scaleSetEvictionPolicy`](#parameter-agentpoolsscalesetevictionpolicy) | string | The scale set eviction policy of the agent pool. | +| [`scaleSetPriority`](#parameter-agentpoolsscalesetpriority) | string | The scale set priority of the agent pool. | +| [`sourceResourceId`](#parameter-agentpoolssourceresourceid) | string | The source resource ID to create the agent pool from. | +| [`spotMaxPrice`](#parameter-agentpoolsspotmaxprice) | int | The spot max price of the agent pool. | +| [`tags`](#parameter-agentpoolstags) | object | The tags of the agent pool. | +| [`type`](#parameter-agentpoolstype) | string | The type of the agent pool. | +| [`vmSize`](#parameter-agentpoolsvmsize) | string | The VM size of the agent pool. | +| [`vnetSubnetID`](#parameter-agentpoolsvnetsubnetid) | string | The VNet subnet ID of the agent pool. | +| [`workloadRuntime`](#parameter-agentpoolsworkloadruntime) | string | The workload runtime of the agent pool. | + +### Parameter: `agentPools.name` + +The name of the agent pool. + +- Required: Yes +- Type: string + +### Parameter: `agentPools.availabilityZones` + +The availability zones of the agent pool. + +- Required: No +- Type: array + +### Parameter: `agentPools.count` + +The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `agentPools.enableAutoScaling` + +Whether to enable auto-scaling for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableDefaultTelemetry` + +The enable default telemetry of the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableEncryptionAtHost` + +Whether to enable encryption at host for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableFIPS` + +Whether to enable FIPS for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableNodePublicIP` + +Whether to enable node public IP for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableUltraSSD` + +Whether to enable Ultra SSD for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.gpuInstanceProfile` + +The GPU instance profile of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'MIG1g' + 'MIG2g' + 'MIG3g' + 'MIG4g' + 'MIG7g' + ] + ``` + +### Parameter: `agentPools.kubeletDiskType` + +The kubelet disk type of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.maxCount` + +The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `agentPools.maxPods` + +The maximum number of pods that can run on a node. + +- Required: No +- Type: int + +### Parameter: `agentPools.maxSurge` + +The maximum number of nodes that can be created during an upgrade. + +- Required: No +- Type: string + +### Parameter: `agentPools.minCount` + +The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `agentPools.minPods` + +The minimum number of pods that can run on a node. + +- Required: No +- Type: int + +### Parameter: `agentPools.mode` + +The mode of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'System' + 'User' + ] + ``` + +### Parameter: `agentPools.nodeLabels` + +The node labels of the agent pool. + +- Required: No +- Type: object + +### Parameter: `agentPools.nodePublicIpPrefixId` + +The node public IP prefix ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.nodeTaints` + +The node taints of the agent pool. + +- Required: No +- Type: array + +### Parameter: `agentPools.orchestratorVersion` + +The Kubernetes version of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.osDiskSizeGB` + +The OS disk size in GB of the agent pool. + +- Required: No +- Type: int + +### Parameter: `agentPools.osDiskType` + +The OS disk type of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.osSku` + +The OS SKU of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.osType` + +The OS type of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `agentPools.podSubnetId` + +The pod subnet ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.proximityPlacementGroupResourceId` + +The proximity placement group resource ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.scaleDownMode` + +The scale down mode of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Deallocate' + 'Delete' + ] + ``` + +### Parameter: `agentPools.scaleSetEvictionPolicy` + +The scale set eviction policy of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Deallocate' + 'Delete' + ] + ``` + +### Parameter: `agentPools.scaleSetPriority` + +The scale set priority of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Low' + 'Regular' + 'Spot' + ] + ``` + +### Parameter: `agentPools.sourceResourceId` + +The source resource ID to create the agent pool from. + +- Required: No +- Type: string + +### Parameter: `agentPools.spotMaxPrice` + +The spot max price of the agent pool. + +- Required: No +- Type: int + +### Parameter: `agentPools.tags` + +The tags of the agent pool. + +- Required: No +- Type: object + +### Parameter: `agentPools.type` + +The type of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AvailabilitySet' + 'VirtualMachineScaleSets' + ] + ``` + +### Parameter: `agentPools.vmSize` + +The VM size of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.vnetSubnetID` + +The VNet subnet ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.workloadRuntime` + +The workload runtime of the agent pool. + +- Required: No +- Type: string + +### Parameter: `aksClusterRoleAssignmentName` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `containerRegistryRoleName` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `dnsPrefix` + +Specifies the DNS prefix specified when creating the managed cluster. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `dnsServiceIP` + +Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `kubernetesVersion` + +Kubernetes Version. + +- Required: No +- Type: string +- Default: `'1.29'` + +### Parameter: `location` + +Specifies the location of AKS cluster. It picks up Resource Group's location by default. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `monitoringWorkspaceResourceId` + +Resource ID of the monitoring log analytics workspace. + +- Required: No +- Type: string + +### Parameter: `networkDataplane` + +Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'azure' + 'cilium' + ] + ``` + +### Parameter: `networkPlugin` + +Network plugin used for building the Kubernetes network. + +- Required: No +- Type: string +- Default: `'azure'` +- Allowed: + ```Bicep + [ + 'azure' + 'kubenet' + ] + ``` + +### Parameter: `networkPluginMode` + +Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'overlay' + ] + ``` + +### Parameter: `networkPolicy` + +Specifies the network policy used for building Kubernetes network. - calico or azure. + +- Required: No +- Type: string +- Default: `'azure'` +- Allowed: + ```Bicep + [ + 'azure' + 'calico' + ] + ``` + +### Parameter: `nodeResourceGroupName` + +The name of the resource group for the managed resources of the AKS cluster. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `podCidr` + +Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used. + +- Required: No +- Type: string + +### Parameter: `principalType` + +The type of principal to assign application roles. + +- Required: No +- Type: string +- Default: `'User'` +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### 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 networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `scopeMaps` + +Scope maps setting. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`actions`](#parameter-scopemapsactions) | array | The list of scoped permissions for registry artifacts. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-scopemapsdescription) | string | The user friendly description of the scope map. | +| [`name`](#parameter-scopemapsname) | string | The name of the scope map. | + +### Parameter: `scopeMaps.actions` + +The list of scoped permissions for registry artifacts. + +- Required: Yes +- Type: array + +### Parameter: `scopeMaps.description` + +The user friendly description of the scope map. + +- Required: No +- Type: string + +### Parameter: `scopeMaps.name` + +The name of the scope map. + +- Required: No +- Type: string + +### Parameter: `serviceCidr` + +A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges. + +- Required: No +- Type: string + +### Parameter: `skuTier` + +Tier of a managed cluster SKU. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Free' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `sshPublicKey` + +Specifies the SSH RSA public key string for the Linux nodes. + +- Required: No +- Type: string + +### Parameter: `tags` + +Custom tags to apply to the AKS resources. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `webApplicationRoutingEnabled` + +Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. + +- Required: No +- Type: bool + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `containerRegistryLoginServer` | string | The login server for the container registry. | +| `containerRegistryName` | string | The resource name of the ACR. | +| `managedClusterClientId` | string | The Client ID of the AKS identity. | +| `managedClusterName` | string | The resource name of the AKS cluster. | +| `managedClusterObjectId` | string | The Object ID of the AKS identity. | +| `managedClusterResourceId` | string | The resource ID of the AKS cluster. | +| `resourceGroupName` | string | The resource group the application insights components were deployed into. | + +## 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/container-registry/registry:0.4.0` | Remote reference | +| `br/public:avm/res/container-service/managed-cluster:0.3.0` | Remote reference | +| `br/public:avm/res/key-vault/vault: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/ptn/azd/aks/main.bicep b/avm/ptn/azd/aks/main.bicep new file mode 100644 index 0000000000..799530cbed --- /dev/null +++ b/avm/ptn/azd/aks/main.bicep @@ -0,0 +1,466 @@ +metadata name = 'Azd AKS' +metadata description = '''Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the parent managed cluster. Required if the template is used in a standalone deployment.') +param name string + +@description('Required. Name of your Azure Container Registry.') +@minLength(5) +@maxLength(50) +param containerRegistryName string + +@description('Required. The name of the connected log analytics workspace.') +param logAnalyticsName string + +@description('Required. Name of the Key Vault. Must be globally unique.') +@maxLength(24) +param keyVaultName string + +@description('Optional. Specifies the location of AKS cluster. It picks up Resource Group\'s location by default.') +param location string = resourceGroup().location + +@description('Optional. Custom tags to apply to the AKS resources.') +param tags object = {} + +@description('Optional. Network plugin used for building the Kubernetes network.') +@allowed(['azure', 'kubenet']) +param networkPlugin string = 'azure' + +@description('Optional. Specifies the network policy used for building Kubernetes network. - calico or azure.') +@allowed(['azure', 'calico']) +param networkPolicy string = 'azure' + +@description('Optional. Specifies the DNS prefix specified when creating the managed cluster.') +param dnsPrefix string = name + +@description('Optional. The name of the resource group for the managed resources of the AKS cluster.') +param nodeResourceGroupName string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Required. Id of the user or app to assign application roles.') +param principalId string + +@description('Optional. The type of principal to assign application roles.') +@allowed(['Device', 'ForeignGroup', 'Group', 'ServicePrincipal', 'User']) +param principalType string = 'User' + +@description('Optional. Kubernetes Version.') +param kubernetesVersion string = '1.29' + +@description('Optional. Tier of a managed cluster SKU.') +@allowed([ + 'Free' + 'Premium' + 'Standard' +]) +param skuTier string = 'Standard' + +@description('Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin.') +@allowed([ + 'azure' + 'cilium' +]) +param networkDataplane string? + +@description('Optional. Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin.') +@allowed([ + 'overlay' +]) +param networkPluginMode string? + +@description('Optional. Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used.') +param podCidr string? + +@description('Optional. A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges.') +param serviceCidr string? + +@description('Optional. Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr.') +param dnsServiceIP string? + +@description('Optional. Specifies the SSH RSA public key string for the Linux nodes.') +param sshPublicKey string? + +@description('Optional. Specifies whether to enable Azure RBAC for Kubernetes authorization.') +param aadProfileEnableAzureRBAC bool = false + +@description('Conditional. Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`.') +param appGatewayResourceId string? + +@description('Optional. Resource ID of the monitoring log analytics workspace.') +param monitoringWorkspaceResourceId string? + +@description('Optional. Define one or more secondary/additional agent pools.') +param agentPools agentPoolType + +@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 networkRuleSetIpRules are not set. Note, requires the \'acrSku\' to be \'Premium\'.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Scope maps setting.') +param scopeMaps scopeMapsType + +@description('Optional. Specifies whether the webApplicationRoutingEnabled add-on is enabled or not.') +param webApplicationRoutingEnabled bool? + +@description('Optional. Tier of your Azure container registry.') +@allowed([ + 'Basic' + 'Premium' + 'Standard' +]) +param acrSku string = 'Standard' + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param containerRegistryRoleName string? + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param aksClusterRoleAssignmentName string? + +var aksClusterAdminRole = subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b' +) + +var acrPullRole = subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7f951dda-4ed3-4680-a7ca-43fe172d538d' +) + +var nodePoolPresets = { + vmSize: 'Standard_DS2_v2' + count: 3 + minCount: 3 + maxCount: 5 + enableAutoScaling: true + availabilityZones: [ + '1' + '2' + '3' + ] +} + +var nodePoolBase = { + osType: 'Linux' + maxPods: 30 + type: 'VirtualMachineScaleSets' + upgradeSettings: { + maxSurge: '33%' + } +} + +var primaryAgentPoolProfile = [ + union({ name: 'npsystem', mode: 'System' }, nodePoolBase, nodePoolPresets) +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-aks.${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 logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' existing = if (!empty(logAnalyticsName)) { + name: logAnalyticsName +} + +module managedCluster 'br/public:avm/res/container-service/managed-cluster:0.3.0' = { + name: '${uniqueString(deployment().name, location)}-managed-cluster' + params: { + name: name + location: location + tags: tags + nodeResourceGroup: nodeResourceGroupName + networkDataplane: networkDataplane + networkPlugin: networkPlugin + networkPluginMode: networkPluginMode + networkPolicy: networkPolicy + podCidr: podCidr + serviceCidr: serviceCidr + dnsServiceIP: dnsServiceIP + kubernetesVersion: kubernetesVersion + sshPublicKey: sshPublicKey + aadProfileEnableAzureRBAC: aadProfileEnableAzureRBAC + skuTier: skuTier + appGatewayResourceId: appGatewayResourceId + monitoringWorkspaceId: monitoringWorkspaceResourceId + managedIdentities: { + systemAssigned: true + } + diagnosticSettings: [ + { + logCategoriesAndGroups: [ + { + category: 'cluster-autoscaler' + enabled: true + } + { + category: 'kube-controller-manager' + enabled: true + } + { + category: 'kube-audit-admin' + enabled: true + } + { + category: 'guard' + enabled: true + } + ] + workspaceResourceId: !empty(logAnalyticsName) ? logAnalytics.id : '' + metricCategories: [ + { + category: 'AllMetrics' + enabled: true + } + ] + } + ] + webApplicationRoutingEnabled: webApplicationRoutingEnabled + primaryAgentPoolProfile: primaryAgentPoolProfile + dnsPrefix: dnsPrefix + agentPools: agentPools + enableTelemetry: enableTelemetry + roleAssignments: [ + { + name: aksClusterRoleAssignmentName + principalId: principalId + principalType: principalType + roleDefinitionIdOrName: aksClusterAdminRole + } + ] + } +} + +module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = { + name: '${uniqueString(deployment().name, location)}-container-registry' + params: { + name: containerRegistryName + location: location + tags: tags + publicNetworkAccess: publicNetworkAccess + scopeMaps: scopeMaps + acrSku: acrSku + enableTelemetry: enableTelemetry + diagnosticSettings: [ + { + logCategoriesAndGroups: [ + { + category: 'ContainerRegistryRepositoryEvents' + enabled: true + } + { + category: 'ContainerRegistryLoginEvents' + enabled: true + } + ] + workspaceResourceId: !empty(logAnalyticsName) ? logAnalytics.id : '' + metricCategories: [ + { + category: 'AllMetrics' + enabled: true + } + ] + } + ] + roleAssignments: [ + { + name: containerRegistryRoleName + principalId: managedCluster.outputs.kubeletIdentityObjectId + roleDefinitionIdOrName: acrPullRole + } + ] + } +} + +module keyVault 'br/public:avm/res/key-vault/vault:0.7.1' = { + name: '${uniqueString(deployment().name, location)}-key-vault' + params: { + name: keyVaultName + enableTelemetry: enableTelemetry + accessPolicies: [ + { + objectId: managedCluster.outputs.kubeletIdentityObjectId + permissions: { + secrets: ['get', 'list'] + } + } + ] + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource group the application insights components were deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource name of the AKS cluster.') +output managedClusterName string = managedCluster.outputs.name + +@description('The Client ID of the AKS identity.') +output managedClusterClientId string = managedCluster.outputs.kubeletIdentityClientId + +@description('The Object ID of the AKS identity.') +output managedClusterObjectId string = managedCluster.outputs.kubeletIdentityObjectId + +@description('The resource ID of the AKS cluster.') +output managedClusterResourceId string = managedCluster.outputs.kubeletIdentityResourceId + +@description('The resource name of the ACR.') +output containerRegistryName string = containerRegistry.outputs.name + +@description('The login server for the container registry.') +output containerRegistryLoginServer string = containerRegistry.outputs.loginServer + +// =============== // +// Definitions // +// =============== // + +type agentPoolType = { + @description('Required. The name of the agent pool.') + name: string + + @description('Optional. The availability zones of the agent pool.') + availabilityZones: string[]? + + @description('Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive).') + count: int? + + @description('Optional. The source resource ID to create the agent pool from.') + sourceResourceId: string? + + @description('Optional. Whether to enable auto-scaling for the agent pool.') + enableAutoScaling: bool? + + @description('Optional. Whether to enable encryption at host for the agent pool.') + enableEncryptionAtHost: bool? + + @description('Optional. Whether to enable FIPS for the agent pool.') + enableFIPS: bool? + + @description('Optional. Whether to enable node public IP for the agent pool.') + enableNodePublicIP: bool? + + @description('Optional. Whether to enable Ultra SSD for the agent pool.') + enableUltraSSD: bool? + + @description('Optional. The GPU instance profile of the agent pool.') + gpuInstanceProfile: ('MIG1g' | 'MIG2g' | 'MIG3g' | 'MIG4g' | 'MIG7g')? + + @description('Optional. The kubelet disk type of the agent pool.') + kubeletDiskType: string? + + @description('Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive).') + maxCount: int? + + @description('Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive).') + minCount: int? + + @description('Optional. The maximum number of pods that can run on a node.') + maxPods: int? + + @description('Optional. The minimum number of pods that can run on a node.') + minPods: int? + + @description('Optional. The mode of the agent pool.') + mode: ('System' | 'User')? + + @description('Optional. The node labels of the agent pool.') + nodeLabels: object? + + @description('Optional. The node public IP prefix ID of the agent pool.') + nodePublicIpPrefixId: string? + + @description('Optional. The node taints of the agent pool.') + nodeTaints: string[]? + + @description('Optional. The Kubernetes version of the agent pool.') + orchestratorVersion: string? + + @description('Optional. The OS disk size in GB of the agent pool.') + osDiskSizeGB: int? + + @description('Optional. The OS disk type of the agent pool.') + osDiskType: string? + + @description('Optional. The OS SKU of the agent pool.') + osSku: string? + + @description('Optional. The OS type of the agent pool.') + osType: ('Linux' | 'Windows')? + + @description('Optional. The pod subnet ID of the agent pool.') + podSubnetId: string? + + @description('Optional. The proximity placement group resource ID of the agent pool.') + proximityPlacementGroupResourceId: string? + + @description('Optional. The scale down mode of the agent pool.') + scaleDownMode: ('Delete' | 'Deallocate')? + + @description('Optional. The scale set eviction policy of the agent pool.') + scaleSetEvictionPolicy: ('Delete' | 'Deallocate')? + + @description('Optional. The scale set priority of the agent pool.') + scaleSetPriority: ('Low' | 'Regular' | 'Spot')? + + @description('Optional. The spot max price of the agent pool.') + spotMaxPrice: int? + + @description('Optional. The tags of the agent pool.') + tags: object? + + @description('Optional. The type of the agent pool.') + type: ('AvailabilitySet' | 'VirtualMachineScaleSets')? + + @description('Optional. The maximum number of nodes that can be created during an upgrade.') + maxSurge: string? + + @description('Optional. The VM size of the agent pool.') + vmSize: string? + + @description('Optional. The VNet subnet ID of the agent pool.') + vnetSubnetID: string? + + @description('Optional. The workload runtime of the agent pool.') + workloadRuntime: string? + + @description('Optional. The enable default telemetry of the agent pool.') + enableDefaultTelemetry: bool? +}[]? + +type scopeMapsType = { + @description('Optional. The name of the scope map.') + name: string? + + @description('Required. The list of scoped permissions for registry artifacts.') + actions: string[] + + @description('Optional. The user friendly description of the scope map.') + description: string? +}[]? diff --git a/avm/ptn/azd/aks/main.json b/avm/ptn/azd/aks/main.json new file mode 100644 index 0000000000..ea34740356 --- /dev/null +++ b/avm/ptn/azd/aks/main.json @@ -0,0 +1,9163 @@ +{ + "$schema": "https://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": "1486388262618258805" + }, + "name": "Azd AKS", + "description": "Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "agentPoolType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the agent pool." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The availability zones of the agent pool." + } + }, + "count": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "sourceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source resource ID to create the agent pool from." + } + }, + "enableAutoScaling": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable auto-scaling for the agent pool." + } + }, + "enableEncryptionAtHost": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable encryption at host for the agent pool." + } + }, + "enableFIPS": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable FIPS for the agent pool." + } + }, + "enableNodePublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable node public IP for the agent pool." + } + }, + "enableUltraSSD": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable Ultra SSD for the agent pool." + } + }, + "gpuInstanceProfile": { + "type": "string", + "allowedValues": [ + "MIG1g", + "MIG2g", + "MIG3g", + "MIG4g", + "MIG7g" + ], + "nullable": true, + "metadata": { + "description": "Optional. The GPU instance profile of the agent pool." + } + }, + "kubeletDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The kubelet disk type of the agent pool." + } + }, + "maxCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "minCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "maxPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of pods that can run on a node." + } + }, + "minPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of pods that can run on a node." + } + }, + "mode": { + "type": "string", + "allowedValues": [ + "System", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The mode of the agent pool." + } + }, + "nodeLabels": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The node labels of the agent pool." + } + }, + "nodePublicIpPrefixId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The node public IP prefix ID of the agent pool." + } + }, + "nodeTaints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The node taints of the agent pool." + } + }, + "orchestratorVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Kubernetes version of the agent pool." + } + }, + "osDiskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk size in GB of the agent pool." + } + }, + "osDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk type of the agent pool." + } + }, + "osSku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS SKU of the agent pool." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "nullable": true, + "metadata": { + "description": "Optional. The OS type of the agent pool." + } + }, + "podSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The pod subnet ID of the agent pool." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The proximity placement group resource ID of the agent pool." + } + }, + "scaleDownMode": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale down mode of the agent pool." + } + }, + "scaleSetEvictionPolicy": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set eviction policy of the agent pool." + } + }, + "scaleSetPriority": { + "type": "string", + "allowedValues": [ + "Low", + "Regular", + "Spot" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set priority of the agent pool." + } + }, + "spotMaxPrice": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The spot max price of the agent pool." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the agent pool." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "AvailabilitySet", + "VirtualMachineScaleSets" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the agent pool." + } + }, + "maxSurge": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of nodes that can be created during an upgrade." + } + }, + "vmSize": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VM size of the agent pool." + } + }, + "vnetSubnetID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VNet subnet ID of the agent pool." + } + }, + "workloadRuntime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The workload runtime of the agent pool." + } + }, + "enableDefaultTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The enable default telemetry of the agent pool." + } + } + } + }, + "nullable": true + }, + "scopeMapsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent managed cluster. Required if the template is used in a standalone deployment." + } + }, + "containerRegistryName": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Required. The name of the connected log analytics workspace." + } + }, + "keyVaultName": { + "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. Specifies the location of AKS cluster. It picks up Resource Group's location by default." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Custom tags to apply to the AKS resources." + } + }, + "networkPlugin": { + "type": "string", + "defaultValue": "azure", + "allowedValues": [ + "azure", + "kubenet" + ], + "metadata": { + "description": "Optional. Network plugin used for building the Kubernetes network." + } + }, + "networkPolicy": { + "type": "string", + "defaultValue": "azure", + "allowedValues": [ + "azure", + "calico" + ], + "metadata": { + "description": "Optional. Specifies the network policy used for building Kubernetes network. - calico or azure." + } + }, + "dnsPrefix": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Specifies the DNS prefix specified when creating the managed cluster." + } + }, + "nodeResourceGroupName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the resource group for the managed resources of the AKS cluster." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. Id of the user or app to assign application roles." + } + }, + "principalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "metadata": { + "description": "Optional. The type of principal to assign application roles." + } + }, + "kubernetesVersion": { + "type": "string", + "defaultValue": "1.29", + "metadata": { + "description": "Optional. Kubernetes Version." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of a managed cluster SKU." + } + }, + "networkDataplane": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "cilium" + ], + "metadata": { + "description": "Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin." + } + }, + "networkPluginMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "overlay" + ], + "metadata": { + "description": "Optional. Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin." + } + }, + "podCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used." + } + }, + "serviceCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges." + } + }, + "dnsServiceIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr." + } + }, + "sshPublicKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the SSH RSA public key string for the Linux nodes." + } + }, + "aadProfileEnableAzureRBAC": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to enable Azure RBAC for Kubernetes authorization." + } + }, + "appGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`." + } + }, + "monitoringWorkspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the monitoring log analytics workspace." + } + }, + "agentPools": { + "$ref": "#/definitions/agentPoolType", + "metadata": { + "description": "Optional. Define one or more secondary/additional agent pools." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "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 networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "scopeMaps": { + "$ref": "#/definitions/scopeMapsType", + "metadata": { + "description": "Optional. Scope maps setting." + } + }, + "webApplicationRoutingEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the webApplicationRoutingEnabled add-on is enabled or not." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "containerRegistryRoleName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "aksClusterRoleAssignmentName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + } + }, + "variables": { + "aksClusterAdminRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b')]", + "acrPullRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "nodePoolPresets": { + "vmSize": "Standard_DS2_v2", + "count": 3, + "minCount": 3, + "maxCount": 5, + "enableAutoScaling": true, + "availabilityZones": [ + "1", + "2", + "3" + ] + }, + "nodePoolBase": { + "osType": "Linux", + "maxPods": 30, + "type": "VirtualMachineScaleSets", + "upgradeSettings": { + "maxSurge": "33%" + } + }, + "primaryAgentPoolProfile": [ + "[union(createObject('name', 'npsystem', 'mode', 'System'), variables('nodePoolBase'), variables('nodePoolPresets'))]" + ] + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-aks.{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" + } + } + } + } + }, + "logAnalytics": { + "condition": "[not(empty(parameters('logAnalyticsName')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-12-01-preview", + "name": "[parameters('logAnalyticsName')]" + }, + "managedCluster": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-managed-cluster', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "nodeResourceGroup": { + "value": "[parameters('nodeResourceGroupName')]" + }, + "networkDataplane": { + "value": "[parameters('networkDataplane')]" + }, + "networkPlugin": { + "value": "[parameters('networkPlugin')]" + }, + "networkPluginMode": { + "value": "[parameters('networkPluginMode')]" + }, + "networkPolicy": { + "value": "[parameters('networkPolicy')]" + }, + "podCidr": { + "value": "[parameters('podCidr')]" + }, + "serviceCidr": { + "value": "[parameters('serviceCidr')]" + }, + "dnsServiceIP": { + "value": "[parameters('dnsServiceIP')]" + }, + "kubernetesVersion": { + "value": "[parameters('kubernetesVersion')]" + }, + "sshPublicKey": { + "value": "[parameters('sshPublicKey')]" + }, + "aadProfileEnableAzureRBAC": { + "value": "[parameters('aadProfileEnableAzureRBAC')]" + }, + "skuTier": { + "value": "[parameters('skuTier')]" + }, + "appGatewayResourceId": { + "value": "[parameters('appGatewayResourceId')]" + }, + "monitoringWorkspaceId": { + "value": "[parameters('monitoringWorkspaceResourceId')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "diagnosticSettings": { + "value": [ + { + "logCategoriesAndGroups": [ + { + "category": "cluster-autoscaler", + "enabled": true + }, + { + "category": "kube-controller-manager", + "enabled": true + }, + { + "category": "kube-audit-admin", + "enabled": true + }, + { + "category": "guard", + "enabled": true + } + ], + "workspaceResourceId": "[if(not(empty(parameters('logAnalyticsName'))), resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName')), '')]", + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "webApplicationRoutingEnabled": { + "value": "[parameters('webApplicationRoutingEnabled')]" + }, + "primaryAgentPoolProfile": { + "value": "[variables('primaryAgentPoolProfile')]" + }, + "dnsPrefix": { + "value": "[parameters('dnsPrefix')]" + }, + "agentPools": { + "value": "[parameters('agentPools')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "name": "[parameters('aksClusterRoleAssignmentName')]", + "principalId": "[parameters('principalId')]", + "principalType": "[parameters('principalType')]", + "roleDefinitionIdOrName": "[variables('aksClusterAdminRole')]" + } + ] + } + }, + "template": { + "$schema": "https://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": "17708769259435874319" + }, + "name": "Azure Kubernetes Service (AKS) Managed Clusters", + "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "agentPoolType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The name of the agent pool." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The availability zones of the agent pool." + } + }, + "count": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "sourceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source resource ID to create the agent pool from." + } + }, + "enableAutoScaling": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable auto-scaling for the agent pool." + } + }, + "enableEncryptionAtHost": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable encryption at host for the agent pool." + } + }, + "enableFIPS": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable FIPS for the agent pool." + } + }, + "enableNodePublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable node public IP for the agent pool." + } + }, + "enableUltraSSD": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable Ultra SSD for the agent pool." + } + }, + "gpuInstanceProfile": { + "type": "string", + "allowedValues": [ + "MIG1g", + "MIG2g", + "MIG3g", + "MIG4g", + "MIG7g" + ], + "nullable": true, + "metadata": { + "description": "Optional. The GPU instance profile of the agent pool." + } + }, + "kubeletDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The kubelet disk type of the agent pool." + } + }, + "maxCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "minCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "maxPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of pods that can run on a node." + } + }, + "minPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of pods that can run on a node." + } + }, + "mode": { + "type": "string", + "allowedValues": [ + "System", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The mode of the agent pool." + } + }, + "nodeLabels": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The node labels of the agent pool." + } + }, + "nodePublicIpPrefixId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The node public IP prefix ID of the agent pool." + } + }, + "nodeTaints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The node taints of the agent pool." + } + }, + "orchestratorVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Kubernetes version of the agent pool." + } + }, + "osDiskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk size in GB of the agent pool." + } + }, + "osDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk type of the agent pool." + } + }, + "osSku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS SKU of the agent pool." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "nullable": true, + "metadata": { + "description": "Optional. The OS type of the agent pool." + } + }, + "podSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The pod subnet ID of the agent pool." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The proximity placement group resource ID of the agent pool." + } + }, + "scaleDownMode": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale down mode of the agent pool." + } + }, + "scaleSetEvictionPolicy": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set eviction policy of the agent pool." + } + }, + "scaleSetPriority": { + "type": "string", + "allowedValues": [ + "Low", + "Regular", + "Spot" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set priority of the agent pool." + } + }, + "spotMaxPrice": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The spot max price of the agent pool." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the agent pool." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "AvailabilitySet", + "VirtualMachineScaleSets" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the agent pool." + } + }, + "maxSurge": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of nodes that can be created during an upgrade." + } + }, + "vmSize": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VM size of the agent pool." + } + }, + "vnetSubnetID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VNet subnet ID of the agent pool." + } + }, + "workloadRuntime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The workload runtime of the agent pool." + } + }, + "enableDefaultTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The enable default telemetry of the agent pool." + } + } + } + }, + "nullable": true + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourcesIds": { + "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." + } + }, + "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 + }, + "fluxConfigurationProtectedSettingsType": { + "type": "object", + "properties": { + "sshPrivateKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SSH private key to use for Git authentication." + } + } + }, + "nullable": true + }, + "extensionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The name of the extension." + } + }, + "releaseNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension Release must be placed." + } + }, + "targetNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension will be created for an Namespace scoped extension." + } + }, + "releaseTrain": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The release train of the extension." + } + }, + "configurationProtectedSettings": { + "$ref": "#/definitions/fluxConfigurationProtectedSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The configuration protected settings of the extension." + } + }, + "configurationSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The configuration settings of the extension." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the extension." + } + }, + "configurations": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The flux configurations of the extension." + } + } + }, + "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'." + } + }, + "keyVaultNetworkAccess": { + "type": "string", + "allowedValues": [ + "Private", + "Public" + ], + "metadata": { + "description": "Required. Network access of key vault. The possible values are Public and Private. Public means the key vault allows public access from all networks. Private means the key vault disables public access and enables private link. The default value is Public." + } + } + }, + "nullable": true + }, + "maintenanceConfigurationType": { + "type": "object", + "properties": { + "maintenanceWindow": { + "type": "object", + "metadata": { + "description": "Required. Maintenance window for the maintenance configuration." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the AKS cluster." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Specifies the location of AKS cluster. It picks up Resource Group's location by default." + } + }, + "dnsPrefix": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Specifies the DNS prefix specified when creating the managed cluster." + } + }, + "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." + } + }, + "networkDataplane": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "cilium" + ], + "metadata": { + "description": "Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin." + } + }, + "networkPlugin": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "kubenet" + ], + "metadata": { + "description": "Optional. Specifies the network plugin used for building Kubernetes network." + } + }, + "networkPluginMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "overlay" + ], + "metadata": { + "description": "Optional. Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin." + } + }, + "networkPolicy": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "calico" + ], + "metadata": { + "description": "Optional. Specifies the network policy used for building Kubernetes network. - calico or azure." + } + }, + "podCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used." + } + }, + "serviceCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges." + } + }, + "dnsServiceIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr." + } + }, + "loadBalancerSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the sku of the load balancer used by the virtual machine scale sets used by nodepools." + } + }, + "managedOutboundIPCount": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Outbound IP Count for the Load balancer." + } + }, + "backendPoolType": { + "type": "string", + "defaultValue": "NodeIPConfiguration", + "allowedValues": [ + "NodeIP", + "NodeIPConfiguration" + ], + "metadata": { + "description": "Optional. The type of the managed inbound Load Balancer BackendPool." + } + }, + "outboundType": { + "type": "string", + "defaultValue": "loadBalancer", + "allowedValues": [ + "loadBalancer", + "userDefinedRouting", + "managedNATGateway", + "userAssignedNATGateway" + ], + "metadata": { + "description": "Optional. Specifies outbound (egress) routing method." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of a managed cluster SKU." + } + }, + "kubernetesVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Version of Kubernetes specified when creating the managed cluster." + } + }, + "adminUsername": { + "type": "string", + "defaultValue": "azureuser", + "metadata": { + "description": "Optional. Specifies the administrator username of Linux virtual machines." + } + }, + "sshPublicKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the SSH RSA public key string for the Linux nodes." + } + }, + "aksServicePrincipalProfile": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Conditional. Information about a service principal identity for the cluster to use for manipulating Azure APIs. Required if no managed identities are assigned to the cluster." + } + }, + "aadProfileClientAppID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The client AAD application ID." + } + }, + "aadProfileServerAppID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The server AAD application ID." + } + }, + "aadProfileServerAppSecret": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The server AAD application secret." + } + }, + "aadProfileTenantId": { + "type": "string", + "defaultValue": "[subscription().tenantId]", + "metadata": { + "description": "Optional. Specifies the tenant ID of the Azure Active Directory used by the AKS cluster for authentication." + } + }, + "aadProfileAdminGroupObjectIDs": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the AAD group object IDs that will have admin role of the cluster." + } + }, + "aadProfileManaged": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether to enable managed AAD integration." + } + }, + "enableRBAC": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether to enable Kubernetes Role-Based Access Control." + } + }, + "aadProfileEnableAzureRBAC": { + "type": "bool", + "defaultValue": "[parameters('enableRBAC')]", + "metadata": { + "description": "Optional. Specifies whether to enable Azure RBAC for Kubernetes authorization." + } + }, + "disableLocalAccounts": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If set to true, getting static credentials will be disabled for this cluster. This must only be used on Managed Clusters that are AAD enabled." + } + }, + "nodeResourceGroup": { + "type": "string", + "defaultValue": "[format('{0}_aks_{1}_nodes', resourceGroup().name, parameters('name'))]", + "metadata": { + "description": "Optional. Name of the resource group containing agent pool nodes." + } + }, + "authorizedIPRanges": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. IP ranges are specified in CIDR format, e.g. 137.117.106.88/29. This feature is not compatible with clusters that use Public IP Per Node, or clusters that are using a Basic Load Balancer." + } + }, + "disableRunCommand": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to disable run command for the cluster or not." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Allow or deny public network access for AKS." + } + }, + "enablePrivateCluster": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to create the cluster as a private cluster or not." + } + }, + "enablePrivateClusterPublicFQDN": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to create additional public FQDN for private cluster or not." + } + }, + "privateDNSZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Private DNS Zone configuration. Set to 'system' and AKS will create a private DNS zone in the node resource group. Set to '' to disable private DNS Zone creation and use public DNS. Supply the resource ID here of an existing Private DNS zone to use an existing zone." + } + }, + "primaryAgentPoolProfile": { + "type": "array", + "metadata": { + "description": "Required. Properties of the primary agent pool." + } + }, + "agentPools": { + "$ref": "#/definitions/agentPoolType", + "metadata": { + "description": "Optional. Define one or more secondary/additional agent pools." + } + }, + "maintenanceConfiguration": { + "$ref": "#/definitions/maintenanceConfigurationType", + "metadata": { + "description": "Optional. Whether or not to use AKS Automatic mode." + } + }, + "costAnalysisEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the cost analysis add-on is enabled or not. If Enabled `enableStorageProfileDiskCSIDriver` is set to true as it is needed." + } + }, + "httpApplicationRoutingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the httpApplicationRouting add-on is enabled or not." + } + }, + "webApplicationRoutingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the webApplicationRoutingEnabled add-on is enabled or not." + } + }, + "dnsZoneResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource ID of connected DNS zone. It will be ignored if `webApplicationRoutingEnabled` is set to `false`." + } + }, + "enableDnsZoneContributorRoleAssignment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether assing the DNS zone contributor role to the cluster service principal. It will be ignored if `webApplicationRoutingEnabled` is set to `false` or `dnsZoneResourceId` not provided." + } + }, + "ingressApplicationGatewayEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the ingressApplicationGateway (AGIC) add-on is enabled or not." + } + }, + "appGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`." + } + }, + "aciConnectorLinuxEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the aciConnectorLinux add-on is enabled or not." + } + }, + "azurePolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the azurepolicy add-on is enabled or not. For security reasons, this setting should be enabled." + } + }, + "openServiceMeshEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the openServiceMesh add-on is enabled or not." + } + }, + "azurePolicyVersion": { + "type": "string", + "defaultValue": "v2", + "metadata": { + "description": "Optional. Specifies the azure policy version to use." + } + }, + "kubeDashboardEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the kubeDashboard add-on is enabled or not." + } + }, + "enableKeyvaultSecretsProvider": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the KeyvaultSecretsProvider add-on is enabled or not." + } + }, + "enableSecretRotation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the KeyvaultSecretsProvider add-on uses secret rotation." + } + }, + "autoScalerProfileScanInterval": { + "type": "string", + "defaultValue": "10s", + "metadata": { + "description": "Optional. Specifies the scan interval of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownDelayAfterAdd": { + "type": "string", + "defaultValue": "10m", + "metadata": { + "description": "Optional. Specifies the scale down delay after add of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownDelayAfterDelete": { + "type": "string", + "defaultValue": "20s", + "metadata": { + "description": "Optional. Specifies the scale down delay after delete of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownDelayAfterFailure": { + "type": "string", + "defaultValue": "3m", + "metadata": { + "description": "Optional. Specifies scale down delay after failure of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownUnneededTime": { + "type": "string", + "defaultValue": "10m", + "metadata": { + "description": "Optional. Specifies the scale down unneeded time of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownUnreadyTime": { + "type": "string", + "defaultValue": "20m", + "metadata": { + "description": "Optional. Specifies the scale down unready time of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileUtilizationThreshold": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. Specifies the utilization threshold of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileMaxGracefulTerminationSec": { + "type": "string", + "defaultValue": "600", + "metadata": { + "description": "Optional. Specifies the max graceful termination time interval in seconds for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileBalanceSimilarNodeGroups": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies the balance of similar node groups for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileExpander": { + "type": "string", + "defaultValue": "random", + "allowedValues": [ + "least-waste", + "most-pods", + "priority", + "random" + ], + "metadata": { + "description": "Optional. Specifies the expand strategy for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileMaxEmptyBulkDelete": { + "type": "string", + "defaultValue": "10", + "metadata": { + "description": "Optional. Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileMaxNodeProvisionTime": { + "type": "string", + "defaultValue": "15m", + "metadata": { + "description": "Optional. Specifies the maximum node provisioning time for the auto-scaler of the AKS cluster. Values must be an integer followed by an \"m\". No unit of time other than minutes (m) is supported." + } + }, + "autoScalerProfileMaxTotalUnreadyPercentage": { + "type": "string", + "defaultValue": "45", + "metadata": { + "description": "Optional. Specifies the mximum total unready percentage for the auto-scaler of the AKS cluster. The maximum is 100 and the minimum is 0." + } + }, + "autoScalerProfileNewPodScaleUpDelay": { + "type": "string", + "defaultValue": "0s", + "metadata": { + "description": "Optional. For scenarios like burst/batch scale where you do not want CA to act before the kubernetes scheduler could schedule all the pods, you can tell CA to ignore unscheduled pods before they are a certain age. Values must be an integer followed by a unit (\"s\" for seconds, \"m\" for minutes, \"h\" for hours, etc)." + } + }, + "autoScalerProfileOkTotalUnreadyCount": { + "type": "string", + "defaultValue": "3", + "metadata": { + "description": "Optional. Specifies the OK total unready count for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileSkipNodesWithLocalStorage": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if nodes with local storage should be skipped for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileSkipNodesWithSystemPods": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if nodes with system pods should be skipped for the auto-scaler of the AKS cluster." + } + }, + "autoUpgradeProfileUpgradeChannel": { + "type": "string", + "defaultValue": "stable", + "allowedValues": [ + "node-image", + "none", + "patch", + "rapid", + "stable" + ], + "metadata": { + "description": "Optional. Auto-upgrade channel on the AKS cluster." + } + }, + "podIdentityProfileAllowNetworkPluginKubenet": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Running in Kubenet is disabled by default due to the security related nature of AAD Pod Identity and the risks of IP spoofing." + } + }, + "podIdentityProfileEnable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the pod identity addon is enabled." + } + }, + "podIdentityProfileUserAssignedIdentities": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The pod identities to use in the cluster." + } + }, + "podIdentityProfileUserAssignedIdentityExceptions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The pod identity exceptions to allow." + } + }, + "enableOidcIssuerProfile": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the The OIDC issuer profile of the Managed Cluster is enabled." + } + }, + "enableWorkloadIdentity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Workload Identity. Requires OIDC issuer profile to be enabled." + } + }, + "enableAzureDefender": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Azure Defender." + } + }, + "enableImageCleaner": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Image Cleaner for Kubernetes." + } + }, + "imageCleanerIntervalHours": { + "type": "int", + "defaultValue": 24, + "minValue": 24, + "metadata": { + "description": "Optional. The interval in hours Image Cleaner will run. The maximum value is three months." + } + }, + "enablePodSecurityPolicy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Kubernetes pod security policy. Requires enabling the pod security policy feature flag on the subscription." + } + }, + "enableStorageProfileBlobCSIDriver": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the AzureBlob CSI Driver for the storage profile is enabled." + } + }, + "enableStorageProfileDiskCSIDriver": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the AzureDisk CSI Driver for the storage profile is enabled." + } + }, + "enableStorageProfileFileCSIDriver": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the AzureFile CSI Driver for the storage profile is enabled." + } + }, + "enableStorageProfileSnapshotController": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the snapshot controller for the storage profile is enabled." + } + }, + "supportPlan": { + "type": "string", + "defaultValue": "KubernetesOfficial", + "allowedValues": [ + "AKSLongTermSupport", + "KubernetesOfficial" + ], + "metadata": { + "description": "Optional. The support plan for the Managed Cluster." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "omsAgentEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the OMS agent is enabled." + } + }, + "monitoringWorkspaceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the monitoring log analytics workspace." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "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." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the disc encryption set to apply to the cluster. For security reasons, this value should be provided." + } + }, + "fluxExtension": { + "$ref": "#/definitions/extensionType", + "metadata": { + "description": "Optional. Settings and configurations for the flux extension." + } + }, + "httpProxyConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configurations for provisioning the cluster with HTTP proxy servers." + } + }, + "identityProfile": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Identities associated with the cluster." + } + }, + "kedaAddon": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables Kubernetes Event-driven Autoscaling (KEDA)." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "enableAzureMonitorProfileMetrics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the metric state of the kubenetes cluster is enabled." + } + }, + "enableContainerInsights": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if Azure Monitor Container Insights Logs Addon is enabled." + } + }, + "disableCustomMetrics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether custom metrics collection has to be disabled or not. If not specified the default is false. No custom metrics will be emitted if this field is false but the container insights enabled field is false." + } + }, + "disablePrometheusMetricsScraping": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether prometheus metrics scraping is disabled or not. If not specified the default is false. No prometheus metrics will be emitted if this field is false but the container insights enabled field is false." + } + }, + "syslogPort": { + "type": "int", + "defaultValue": 28330, + "metadata": { + "description": "Optional. The syslog host port. If not specified, the default port is 28330." + } + }, + "metricLabelsAllowlist": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A comma-separated list of kubernetes cluster metrics labels." + } + }, + "metricAnnotationsAllowList": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A comma-separated list of Kubernetes cluster metrics annotations." + } + } + }, + "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'), 'userAssignedResourcesIds'), 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'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Azure Kubernetes Fleet Manager Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '63bb64ad-9799-4770-b5c3-24ed299a07bf')]", + "Azure Kubernetes Fleet Manager RBAC Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '434fb43a-c01c-447e-9f67-c3ad923cfaba')]", + "Azure Kubernetes Fleet Manager RBAC Cluster Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18ab4d3d-a1bf-4477-8ad9-8359bc988f69')]", + "Azure Kubernetes Fleet Manager RBAC Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '30b27cfc-9c84-438e-b0ce-70e35255df80')]", + "Azure Kubernetes Fleet Manager RBAC Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5af6afb3-c06c-4fa4-8848-71a8aee05683')]", + "Azure Kubernetes Service Cluster Admin Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0ab0b1a8-8aac-4efd-b8c2-3ee1fb270be8')]", + "Azure Kubernetes Service Cluster Monitoring User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1afdec4b-e479-420e-99e7-f82237c7c5e6')]", + "Azure Kubernetes Service Cluster User Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4abbcc35-e782-43d8-92c5-2d3f1bd2253f')]", + "Azure Kubernetes Service Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ed7f3fbd-7b88-4dd4-9017-9adb7ce333f8')]", + "Azure Kubernetes Service RBAC Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3498e952-d568-435e-9b2c-8d77e338d7f7')]", + "Azure Kubernetes Service RBAC Cluster Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b')]", + "Azure Kubernetes Service RBAC Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f6c6a51-bcf8-42ba-9220-52d62157d7db')]", + "Azure Kubernetes Service RBAC Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7ffa36f-339b-4b5c-8bdf-e2c188b2c0eb')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Kubernetes Agentless Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a2ae44-610b-4500-93be-660a0c5f5ca6')]", + "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": { + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.containerservice-managedcluster.{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" + } + } + } + } + }, + "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'), '/'))]" + }, + "managedCluster": { + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2024-03-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "sku": { + "name": "Base", + "tier": "[parameters('skuTier')]" + }, + "properties": { + "httpProxyConfig": "[parameters('httpProxyConfig')]", + "identityProfile": "[parameters('identityProfile')]", + "diskEncryptionSetID": "[parameters('diskEncryptionSetResourceId')]", + "kubernetesVersion": "[parameters('kubernetesVersion')]", + "dnsPrefix": "[parameters('dnsPrefix')]", + "agentPoolProfiles": "[parameters('primaryAgentPoolProfile')]", + "linuxProfile": "[if(not(empty(parameters('sshPublicKey'))), createObject('adminUsername', parameters('adminUsername'), 'ssh', createObject('publicKeys', createArray(createObject('keyData', coalesce(parameters('sshPublicKey'), ''))))), null())]", + "servicePrincipalProfile": "[parameters('aksServicePrincipalProfile')]", + "metricsProfile": { + "costAnalysis": { + "enabled": "[if(equals(parameters('skuTier'), 'free'), false(), parameters('costAnalysisEnabled'))]" + } + }, + "ingressProfile": { + "webAppRouting": { + "enabled": "[parameters('webApplicationRoutingEnabled')]", + "dnsZoneResourceIds": "[if(not(empty(parameters('dnsZoneResourceId'))), createArray(parameters('dnsZoneResourceId')), null())]" + } + }, + "addonProfiles": { + "httpApplicationRouting": { + "enabled": "[parameters('httpApplicationRoutingEnabled')]" + }, + "ingressApplicationGateway": { + "enabled": "[and(parameters('ingressApplicationGatewayEnabled'), not(empty(parameters('appGatewayResourceId'))))]", + "config": "[if(and(parameters('ingressApplicationGatewayEnabled'), not(empty(parameters('appGatewayResourceId')))), createObject('applicationGatewayId', parameters('appGatewayResourceId'), 'effectiveApplicationGatewayId', parameters('appGatewayResourceId')), null())]" + }, + "omsagent": { + "enabled": "[and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceId'))))]", + "config": "[if(and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceId')))), createObject('logAnalyticsWorkspaceResourceID', parameters('monitoringWorkspaceId')), null())]" + }, + "aciConnectorLinux": { + "enabled": "[parameters('aciConnectorLinuxEnabled')]" + }, + "azurepolicy": { + "enabled": "[parameters('azurePolicyEnabled')]", + "config": "[if(parameters('azurePolicyEnabled'), createObject('version', parameters('azurePolicyVersion')), null())]" + }, + "openServiceMesh": { + "enabled": "[parameters('openServiceMeshEnabled')]", + "config": "[if(parameters('openServiceMeshEnabled'), createObject(), null())]" + }, + "kubeDashboard": { + "enabled": "[parameters('kubeDashboardEnabled')]" + }, + "azureKeyvaultSecretsProvider": { + "enabled": "[parameters('enableKeyvaultSecretsProvider')]", + "config": "[if(parameters('enableKeyvaultSecretsProvider'), createObject('enableSecretRotation', toLower(string(parameters('enableSecretRotation')))), null())]" + } + }, + "oidcIssuerProfile": "[if(parameters('enableOidcIssuerProfile'), createObject('enabled', parameters('enableOidcIssuerProfile')), null())]", + "enableRBAC": "[parameters('enableRBAC')]", + "disableLocalAccounts": "[parameters('disableLocalAccounts')]", + "nodeResourceGroup": "[parameters('nodeResourceGroup')]", + "enablePodSecurityPolicy": "[parameters('enablePodSecurityPolicy')]", + "workloadAutoScalerProfile": { + "keda": { + "enabled": "[parameters('kedaAddon')]" + } + }, + "networkProfile": { + "networkDataplane": "[parameters('networkDataplane')]", + "networkPlugin": "[parameters('networkPlugin')]", + "networkPluginMode": "[parameters('networkPluginMode')]", + "networkPolicy": "[parameters('networkPolicy')]", + "podCidr": "[parameters('podCidr')]", + "serviceCidr": "[parameters('serviceCidr')]", + "dnsServiceIP": "[parameters('dnsServiceIP')]", + "outboundType": "[parameters('outboundType')]", + "loadBalancerSku": "[parameters('loadBalancerSku')]", + "loadBalancerProfile": { + "managedOutboundIPs": "[if(not(equals(parameters('managedOutboundIPCount'), 0)), createObject('count', parameters('managedOutboundIPCount')), null())]", + "effectiveOutboundIPs": [], + "backendPoolType": "[parameters('backendPoolType')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "aadProfile": { + "clientAppID": "[parameters('aadProfileClientAppID')]", + "serverAppID": "[parameters('aadProfileServerAppID')]", + "serverAppSecret": "[parameters('aadProfileServerAppSecret')]", + "managed": "[parameters('aadProfileManaged')]", + "enableAzureRBAC": "[parameters('aadProfileEnableAzureRBAC')]", + "adminGroupObjectIDs": "[parameters('aadProfileAdminGroupObjectIDs')]", + "tenantID": "[parameters('aadProfileTenantId')]" + }, + "autoScalerProfile": { + "balance-similar-node-groups": "[toLower(string(parameters('autoScalerProfileBalanceSimilarNodeGroups')))]", + "expander": "[parameters('autoScalerProfileExpander')]", + "max-empty-bulk-delete": "[parameters('autoScalerProfileMaxEmptyBulkDelete')]", + "max-graceful-termination-sec": "[parameters('autoScalerProfileMaxGracefulTerminationSec')]", + "max-node-provision-time": "[parameters('autoScalerProfileMaxNodeProvisionTime')]", + "max-total-unready-percentage": "[parameters('autoScalerProfileMaxTotalUnreadyPercentage')]", + "new-pod-scale-up-delay": "[parameters('autoScalerProfileNewPodScaleUpDelay')]", + "ok-total-unready-count": "[parameters('autoScalerProfileOkTotalUnreadyCount')]", + "scale-down-delay-after-add": "[parameters('autoScalerProfileScaleDownDelayAfterAdd')]", + "scale-down-delay-after-delete": "[parameters('autoScalerProfileScaleDownDelayAfterDelete')]", + "scale-down-delay-after-failure": "[parameters('autoScalerProfileScaleDownDelayAfterFailure')]", + "scale-down-unneeded-time": "[parameters('autoScalerProfileScaleDownUnneededTime')]", + "scale-down-unready-time": "[parameters('autoScalerProfileScaleDownUnreadyTime')]", + "scale-down-utilization-threshold": "[parameters('autoScalerProfileUtilizationThreshold')]", + "scan-interval": "[parameters('autoScalerProfileScanInterval')]", + "skip-nodes-with-local-storage": "[toLower(string(parameters('autoScalerProfileSkipNodesWithLocalStorage')))]", + "skip-nodes-with-system-pods": "[toLower(string(parameters('autoScalerProfileSkipNodesWithSystemPods')))]" + }, + "autoUpgradeProfile": { + "upgradeChannel": "[parameters('autoUpgradeProfileUpgradeChannel')]" + }, + "apiServerAccessProfile": { + "authorizedIPRanges": "[parameters('authorizedIPRanges')]", + "disableRunCommand": "[parameters('disableRunCommand')]", + "enablePrivateCluster": "[parameters('enablePrivateCluster')]", + "enablePrivateClusterPublicFQDN": "[parameters('enablePrivateClusterPublicFQDN')]", + "privateDNSZone": "[parameters('privateDNSZone')]" + }, + "azureMonitorProfile": { + "containerInsights": "[if(parameters('enableContainerInsights'), createObject('enabled', parameters('enableContainerInsights'), 'logAnalyticsWorkspaceResourceId', if(not(empty(parameters('monitoringWorkspaceId'))), parameters('monitoringWorkspaceId'), null()), 'disableCustomMetrics', parameters('disableCustomMetrics'), 'disablePrometheusMetricsScraping', parameters('disablePrometheusMetricsScraping'), 'syslogPort', parameters('syslogPort')), null())]", + "metrics": "[if(parameters('enableAzureMonitorProfileMetrics'), createObject('enabled', parameters('enableAzureMonitorProfileMetrics'), 'kubeStateMetrics', createObject('metricLabelsAllowlist', parameters('metricLabelsAllowlist'), 'metricAnnotationsAllowList', parameters('metricAnnotationsAllowList'))), null())]" + }, + "podIdentityProfile": { + "allowNetworkPluginKubenet": "[parameters('podIdentityProfileAllowNetworkPluginKubenet')]", + "enabled": "[parameters('podIdentityProfileEnable')]", + "userAssignedIdentities": "[parameters('podIdentityProfileUserAssignedIdentities')]", + "userAssignedIdentityExceptions": "[parameters('podIdentityProfileUserAssignedIdentityExceptions')]" + }, + "securityProfile": { + "defender": "[if(parameters('enableAzureDefender'), createObject('securityMonitoring', createObject('enabled', parameters('enableAzureDefender')), 'logAnalyticsWorkspaceResourceId', parameters('monitoringWorkspaceId')), null())]", + "workloadIdentity": "[if(parameters('enableWorkloadIdentity'), createObject('enabled', parameters('enableWorkloadIdentity')), null())]", + "imageCleaner": "[if(parameters('enableImageCleaner'), createObject('enabled', parameters('enableImageCleaner'), 'intervalHours', parameters('imageCleanerIntervalHours')), null())]" + }, + "storageProfile": { + "blobCSIDriver": { + "enabled": "[parameters('enableStorageProfileBlobCSIDriver')]" + }, + "diskCSIDriver": { + "enabled": "[if(and(equals(parameters('costAnalysisEnabled'), true()), not(equals(parameters('skuTier'), 'free'))), true(), parameters('enableStorageProfileDiskCSIDriver'))]" + }, + "fileCSIDriver": { + "enabled": "[parameters('enableStorageProfileFileCSIDriver')]" + }, + "snapshotController": { + "enabled": "[parameters('enableStorageProfileSnapshotController')]" + } + }, + "supportPlan": "[parameters('supportPlan')]" + } + }, + "managedCluster_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.ContainerService/managedClusters/{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": [ + "managedCluster" + ] + }, + "managedCluster_diagnosticSettings": { + "copy": { + "name": "managedCluster_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerService/managedClusters/{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": [ + "managedCluster" + ] + }, + "managedCluster_roleAssignments": { + "copy": { + "name": "managedCluster_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerService/managedClusters', 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": [ + "managedCluster" + ] + }, + "dnsZone": { + "condition": "[and(and(equals(parameters('enableDnsZoneContributorRoleAssignment'), true()), not(equals(parameters('dnsZoneResourceId'), null()))), parameters('webApplicationRoutingEnabled'))]", + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[last(split(if(not(empty(parameters('dnsZoneResourceId'))), parameters('dnsZoneResourceId'), '/dummmyZone'), '/'))]" + }, + "dnsZone_roleAssignment": { + "condition": "[and(and(equals(parameters('enableDnsZoneContributorRoleAssignment'), true()), not(equals(parameters('dnsZoneResourceId'), null()))), parameters('webApplicationRoutingEnabled'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}', last(split(if(not(empty(parameters('dnsZoneResourceId'))), parameters('dnsZoneResourceId'), '/dummmyZone'), '/')))]", + "name": "[guid(resourceId('Microsoft.Network/dnsZones', last(split(if(not(empty(parameters('dnsZoneResourceId'))), parameters('dnsZoneResourceId'), '/dummmyZone'), '/'))), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314'), 'DNS Zone Contributor')]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "principalId": "[reference('managedCluster').ingressProfile.webAppRouting.identity.objectId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "dnsZone", + "managedCluster" + ] + }, + "managedCluster_maintenanceConfigurations": { + "condition": "[not(empty(parameters('maintenanceConfiguration')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-MaintenanceConfigurations', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "maintenanceWindow": { + "value": "[parameters('maintenanceConfiguration').maintenanceWindow]" + }, + "managedClusterName": { + "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.29.47.4906", + "templateHash": "12168542117744033419" + }, + "name": "Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations", + "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "maintenanceWindow": { + "type": "object", + "metadata": { + "description": "Required. Maintenance window for the maintenance configuration." + } + }, + "managedClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent managed cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "aksManagedAutoUpgradeSchedule", + "metadata": { + "description": "Optional. Name of the maintenance configuration." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerService/managedClusters/maintenanceConfigurations", + "apiVersion": "2023-10-01", + "name": "[format('{0}/{1}', parameters('managedClusterName'), parameters('name'))]", + "properties": { + "maintenanceWindow": "[parameters('maintenanceWindow')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the maintenance configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the maintenance configuration." + }, + "value": "[resourceId('Microsoft.ContainerService/managedClusters/maintenanceConfigurations', parameters('managedClusterName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedCluster" + ] + }, + "managedCluster_agentPools": { + "copy": { + "name": "managedCluster_agentPools", + "count": "[length(coalesce(parameters('agentPools'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-AgentPool-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "managedClusterName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('agentPools'), createArray())[copyIndex()].name]" + }, + "availabilityZones": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'availabilityZones')]" + }, + "count": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'count')]" + }, + "sourceResourceId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'sourceResourceId')]" + }, + "enableAutoScaling": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableAutoScaling')]" + }, + "enableEncryptionAtHost": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableEncryptionAtHost')]" + }, + "enableFIPS": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableFIPS')]" + }, + "enableNodePublicIP": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableNodePublicIP')]" + }, + "enableUltraSSD": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableUltraSSD')]" + }, + "gpuInstanceProfile": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'gpuInstanceProfile')]" + }, + "kubeletDiskType": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'kubeletDiskType')]" + }, + "maxCount": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'maxCount')]" + }, + "maxPods": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'maxPods')]" + }, + "minCount": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'minCount')]" + }, + "mode": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'mode')]" + }, + "nodeLabels": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodeLabels')]" + }, + "nodePublicIpPrefixId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodePublicIpPrefixId')]" + }, + "nodeTaints": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodeTaints')]" + }, + "orchestratorVersion": { + "value": "[coalesce(tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'orchestratorVersion'), parameters('kubernetesVersion'))]" + }, + "osDiskSizeGB": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osDiskSizeGB')]" + }, + "osDiskType": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osDiskType')]" + }, + "osSku": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osSku')]" + }, + "osType": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osType')]" + }, + "podSubnetId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'podSubnetId')]" + }, + "proximityPlacementGroupResourceId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'proximityPlacementGroupResourceId')]" + }, + "scaleDownMode": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'scaleDownMode')]" + }, + "scaleSetEvictionPolicy": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'scaleSetEvictionPolicy')]" + }, + "scaleSetPriority": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'scaleSetPriority')]" + }, + "spotMaxPrice": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'spotMaxPrice')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "type": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'type')]" + }, + "maxSurge": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'maxSurge')]" + }, + "vmSize": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'vmSize')]" + }, + "vnetSubnetId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'vnetSubnetId')]" + }, + "workloadRuntime": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'workloadRuntime')]" + } + }, + "template": { + "$schema": "https://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": "2004205618690542488" + }, + "name": "Azure Kubernetes Service (AKS) Managed Cluster Agent Pools", + "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Agent Pool.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "managedClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent managed cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the agent pool." + } + }, + "availabilityZones": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of Availability zones to use for nodes. This can only be specified if the AgentPoolType property is \"VirtualMachineScaleSets\"." + } + }, + "count": { + "type": "int", + "defaultValue": 1, + "minValue": 0, + "maxValue": 1000, + "metadata": { + "description": "Optional. Desired Number of agents (VMs) specified to host docker containers. Allowed values must be in the range of 0 to 1000 (inclusive) for user pools and in the range of 1 to 1000 (inclusive) for system pools. The default value is 1." + } + }, + "sourceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the ARM ID of the source object to be used to create the target object." + } + }, + "enableAutoScaling": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable auto-scaler." + } + }, + "enableEncryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is only supported on certain VM sizes and in certain Azure regions. For more information, see: /azure/aks/enable-host-encryption. For security reasons, this setting should be enabled." + } + }, + "enableFIPS": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. See Add a FIPS-enabled node pool (https://learn.microsoft.com/en-us/azure/aks/use-multiple-node-pools#add-a-fips-enabled-node-pool-preview) for more details." + } + }, + "enableNodePublicIP": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Some scenarios may require nodes in a node pool to receive their own dedicated public IP addresses. A common scenario is for gaming workloads, where a console needs to make a direct connection to a cloud virtual machine to minimize hops. For more information see assigning a public IP per node (https://learn.microsoft.com/en-us/azure/aks/use-multiple-node-pools#assign-a-public-ip-per-node-for-your-node-pools)." + } + }, + "enableUltraSSD": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable UltraSSD." + } + }, + "gpuInstanceProfile": { + "type": "string", + "nullable": true, + "allowedValues": [ + "MIG1g", + "MIG2g", + "MIG3g", + "MIG4g", + "MIG7g" + ], + "metadata": { + "description": "Optional. GPUInstanceProfile to be used to specify GPU MIG instance profile for supported GPU VM SKU." + } + }, + "kubeletDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the placement of emptyDir volumes, container runtime data root, and Kubelet ephemeral storage." + } + }, + "maxCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of nodes for auto-scaling." + } + }, + "maxPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of pods that can run on a node." + } + }, + "minCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of nodes for auto-scaling." + } + }, + "mode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A cluster must have at least one \"System\" Agent Pool at all times. For additional information on agent pool restrictions and best practices, see: /azure/aks/use-system-pools." + } + }, + "nodeLabels": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The node labels to be persisted across all nodes in agent pool." + } + }, + "nodePublicIpPrefixId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ResourceId of the node PublicIPPrefix." + } + }, + "nodeTaints": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The taints added to new nodes during node pool create and scale. For example, key=value:NoSchedule." + } + }, + "orchestratorVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. As a best practice, you should upgrade all node pools in an AKS cluster to the same Kubernetes version. The node pool version must have the same major version as the control plane. The node pool minor version must be within two minor versions of the control plane version. The node pool version cannot be greater than the control plane version. For more information see upgrading a node pool (https://learn.microsoft.com/en-us/azure/aks/use-multiple-node-pools#upgrade-a-node-pool)." + } + }, + "osDiskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. OS Disk Size in GB to be used to specify the disk size for every machine in the master/agent pool. If you specify 0, it will apply the default osDisk size according to the vmSize specified." + } + }, + "osDiskType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Ephemeral", + "Managed" + ], + "metadata": { + "description": "Optional. The default is \"Ephemeral\" if the VM supports it and has a cache disk larger than the requested OSDiskSizeGB. Otherwise, defaults to \"Managed\". May not be changed after creation. For more information see Ephemeral OS (https://learn.microsoft.com/en-us/azure/aks/cluster-configuration#ephemeral-os)." + } + }, + "osSku": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AzureLinux", + "CBLMariner", + "Ubuntu", + "Windows2019", + "Windows2022" + ], + "metadata": { + "description": "Optional. Specifies the OS SKU used by the agent pool. The default is Ubuntu if OSType is Linux. The default is Windows2019 when Kubernetes <= 1.24 or Windows2022 when Kubernetes >= 1.25 if OSType is Windows." + } + }, + "osType": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Optional. The operating system type. The default is Linux." + } + }, + "podSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Subnet ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID for the Proximity Placement Group." + } + }, + "scaleDownMode": { + "type": "string", + "defaultValue": "Delete", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Describes how VMs are added to or removed from Agent Pools. See [billing states](https://learn.microsoft.com/en-us/azure/virtual-machines/states-billing)." + } + }, + "scaleSetEvictionPolicy": { + "type": "string", + "defaultValue": "Delete", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. The eviction policy specifies what to do with the VM when it is evicted. The default is Delete. For more information about eviction see spot VMs." + } + }, + "scaleSetPriority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Spot" + ], + "metadata": { + "description": "Optional. The Virtual Machine Scale Set priority." + } + }, + "spotMaxPrice": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Possible values are any decimal value greater than zero or -1 which indicates the willingness to pay any on-demand price. For more details on spot pricing, see spot VMs pricing (https://learn.microsoft.com/en-us/azure/virtual-machines/spot-vms#pricing)." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "type": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of Agent Pool." + } + }, + "maxSurge": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This can either be set to an integer (e.g. \"5\") or a percentage (e.g. \"50%\"). If a percentage is specified, it is the percentage of the total agent pool size at the time of the upgrade. For percentages, fractional nodes are rounded up. If not specified, the default is 1. For more information, including best practices, see: /azure/aks/upgrade-cluster#customize-node-surge-upgrade." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "Standard_D2s_v3", + "metadata": { + "description": "Optional. VM size. VM size availability varies by region. If a node contains insufficient compute resources (memory, cpu, etc) pods might fail to run correctly. For more details on restricted VM sizes, see: /azure/aks/quotas-skus-regions." + } + }, + "vnetSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Node Subnet ID. If this is not specified, a VNET and subnet will be generated and used. If no podSubnetID is specified, this applies to nodes and pods, otherwise it applies to just nodes. This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." + } + }, + "workloadRuntime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the type of workload a node can run." + } + } + }, + "resources": { + "managedCluster": { + "existing": true, + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2024-03-02-preview", + "name": "[parameters('managedClusterName')]" + }, + "agentPool": { + "type": "Microsoft.ContainerService/managedClusters/agentPools", + "apiVersion": "2023-07-02-preview", + "name": "[format('{0}/{1}', parameters('managedClusterName'), parameters('name'))]", + "properties": { + "availabilityZones": "[parameters('availabilityZones')]", + "count": "[parameters('count')]", + "creationData": "[if(not(empty(parameters('sourceResourceId'))), createObject('sourceResourceId', parameters('sourceResourceId')), null())]", + "enableAutoScaling": "[parameters('enableAutoScaling')]", + "enableEncryptionAtHost": "[parameters('enableEncryptionAtHost')]", + "enableFIPS": "[parameters('enableFIPS')]", + "enableNodePublicIP": "[parameters('enableNodePublicIP')]", + "enableUltraSSD": "[parameters('enableUltraSSD')]", + "gpuInstanceProfile": "[parameters('gpuInstanceProfile')]", + "kubeletDiskType": "[parameters('kubeletDiskType')]", + "maxCount": "[parameters('maxCount')]", + "maxPods": "[parameters('maxPods')]", + "minCount": "[parameters('minCount')]", + "mode": "[parameters('mode')]", + "nodeLabels": "[parameters('nodeLabels')]", + "nodePublicIPPrefixID": "[parameters('nodePublicIpPrefixId')]", + "nodeTaints": "[parameters('nodeTaints')]", + "orchestratorVersion": "[parameters('orchestratorVersion')]", + "osDiskSizeGB": "[parameters('osDiskSizeGB')]", + "osDiskType": "[parameters('osDiskType')]", + "osSKU": "[parameters('osSku')]", + "osType": "[parameters('osType')]", + "podSubnetID": "[parameters('podSubnetId')]", + "proximityPlacementGroupID": "[parameters('proximityPlacementGroupResourceId')]", + "scaleDownMode": "[parameters('scaleDownMode')]", + "scaleSetEvictionPolicy": "[parameters('scaleSetEvictionPolicy')]", + "scaleSetPriority": "[parameters('scaleSetPriority')]", + "spotMaxPrice": "[parameters('spotMaxPrice')]", + "tags": "[parameters('tags')]", + "type": "[parameters('type')]", + "upgradeSettings": { + "maxSurge": "[parameters('maxSurge')]" + }, + "vmSize": "[parameters('vmSize')]", + "vnetSubnetID": "[parameters('vnetSubnetId')]", + "workloadRuntime": "[parameters('workloadRuntime')]" + }, + "dependsOn": [ + "managedCluster" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the agent pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the agent pool." + }, + "value": "[resourceId('Microsoft.ContainerService/managedClusters/agentPools', parameters('managedClusterName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedCluster" + ] + }, + "managedCluster_extension": { + "condition": "[not(empty(parameters('fluxExtension')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-FluxExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "clusterName": { + "value": "[parameters('name')]" + }, + "configurationProtectedSettings": { + "value": "[tryGet(parameters('fluxExtension'), 'configurationProtectedSettings')]" + }, + "configurationSettings": { + "value": "[tryGet(parameters('fluxExtension'), 'configurationSettings')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionType": { + "value": "microsoft.flux" + }, + "fluxConfigurations": { + "value": "[tryGet(parameters('fluxExtension'), 'configurations')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "flux" + }, + "releaseNamespace": { + "value": "[coalesce(tryGet(parameters('fluxExtension'), 'releaseNamespace'), 'flux-system')]" + }, + "releaseTrain": { + "value": "[coalesce(tryGet(parameters('fluxExtension'), 'releaseTrain'), 'Stable')]" + }, + "version": { + "value": "[tryGet(parameters('fluxExtension'), '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.23.1.45101", + "templateHash": "12293754418506359991" + }, + "name": "Kubernetes Configuration Extensions", + "description": "This module deploys a Kubernetes Configuration Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Flux Configuration." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "clusterName": { + "type": "string", + "metadata": { + "description": "Required. The name of the AKS cluster that should be configured." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "configurationProtectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Configuration settings that are sensitive, as name-value pairs for configuring this extension." + } + }, + "configurationSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configuration settings, as name-value pairs for configuring this extension." + } + }, + "extensionType": { + "type": "string", + "metadata": { + "description": "Required. Type of the extension, of which this resource is an instance of. It must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the extension publisher." + } + }, + "releaseTrain": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ReleaseTrain this extension participates in for auto-upgrade (e.g. Stable, Preview, etc.) - only if autoUpgradeMinorVersion is \"true\"." + } + }, + "releaseNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension Release must be placed, for a Cluster scoped extension. If this namespace does not exist, it will be created." + } + }, + "targetNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension will be created for an Namespace scoped extension. If this namespace does not exist, it will be created." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Version of the extension for this extension, if it is \"pinned\" to a specific version." + } + }, + "fluxConfigurations": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. A list of flux configuraitons." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.kubernetesconfiguration-fluxconfig.{0}.{1}', replace('0.2.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" + } + } + } + } + }, + "managedCluster": { + "existing": true, + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2022-07-01", + "name": "[parameters('clusterName')]" + }, + "extension": { + "type": "Microsoft.KubernetesConfiguration/extensions", + "apiVersion": "2022-03-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('clusterName'))]", + "name": "[parameters('name')]", + "properties": { + "autoUpgradeMinorVersion": "[if(not(empty(parameters('version'))), false(), true())]", + "configurationProtectedSettings": "[parameters('configurationProtectedSettings')]", + "configurationSettings": "[parameters('configurationSettings')]", + "extensionType": "[parameters('extensionType')]", + "releaseTrain": "[parameters('releaseTrain')]", + "scope": { + "cluster": "[if(not(empty(coalesce(parameters('releaseNamespace'), ''))), createObject('releaseNamespace', parameters('releaseNamespace')), null())]", + "namespace": "[if(not(empty(coalesce(parameters('targetNamespace'), ''))), createObject('targetNamespace', parameters('targetNamespace')), null())]" + }, + "version": "[parameters('version')]" + }, + "dependsOn": [ + "managedCluster" + ] + }, + "fluxConfiguration": { + "copy": { + "name": "fluxConfiguration", + "count": "[length(coalesce(parameters('fluxConfigurations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-FluxConfiguration{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "clusterName": { + "value": "[parameters('clusterName')]" + }, + "scope": { + "value": "[coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()].scope]" + }, + "namespace": { + "value": "[coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()].namespace]" + }, + "sourceKind": "[if(contains(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'gitRepository'), createObject('value', 'GitRepository'), createObject('value', 'Bucket'))]", + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'name'), toLower(format('{0}-fluxconfiguration{1}', parameters('clusterName'), copyIndex())))]" + }, + "bucket": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'bucket')]" + }, + "configurationProtectedSettings": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'configurationProtectedSettings')]" + }, + "gitRepository": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'gitRepository')]" + }, + "kustomizations": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'kustomizations')]" + }, + "suspend": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'suspend')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "13420454476526931427" + }, + "name": "Kubernetes Configuration Flux Configurations", + "description": "This module deploys a Kubernetes Configuration Flux Configuration.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Flux Configuration." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "clusterName": { + "type": "string", + "metadata": { + "description": "Required. The name of the AKS cluster that should be configured." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "bucket": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Conditional. Parameters to reconcile to the GitRepository source kind type. Required if `sourceKind` is `Bucket`." + } + }, + "configurationProtectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Key-value pairs of protected configuration settings for the configuration." + } + }, + "gitRepository": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Conditional. Parameters to reconcile to the GitRepository source kind type. Required if `sourceKind` is `GitRepository`." + } + }, + "kustomizations": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Array of kustomizations used to reconcile the artifact pulled by the source type on the cluster." + } + }, + "namespace": { + "type": "string", + "metadata": { + "description": "Required. The namespace to which this configuration is installed to. Maximum of 253 lower case alphanumeric characters, hyphen and period only." + } + }, + "scope": { + "type": "string", + "allowedValues": [ + "cluster", + "namespace" + ], + "metadata": { + "description": "Required. Scope at which the configuration will be installed." + } + }, + "sourceKind": { + "type": "string", + "allowedValues": [ + "Bucket", + "GitRepository" + ], + "metadata": { + "description": "Required. Source Kind to pull the configuration data from." + } + }, + "suspend": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether this configuration should suspend its reconciliation of its kustomizations and sources." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.kubernetesconfiguration-extension.{0}.{1}', replace('0.2.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" + } + } + } + } + }, + "managedCluster": { + "existing": true, + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2022-07-01", + "name": "[parameters('clusterName')]" + }, + "fluxConfiguration": { + "type": "Microsoft.KubernetesConfiguration/fluxConfigurations", + "apiVersion": "2022-03-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('clusterName'))]", + "name": "[parameters('name')]", + "properties": { + "bucket": "[parameters('bucket')]", + "configurationProtectedSettings": "[parameters('configurationProtectedSettings')]", + "gitRepository": "[parameters('gitRepository')]", + "kustomizations": "[parameters('kustomizations')]", + "namespace": "[parameters('namespace')]", + "scope": "[parameters('scope')]", + "sourceKind": "[parameters('sourceKind')]", + "suspend": "[parameters('suspend')]" + }, + "dependsOn": [ + "managedCluster" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the flux configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the flux configuration." + }, + "value": "[extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', parameters('clusterName')), 'Microsoft.KubernetesConfiguration/fluxConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the flux configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "extension", + "managedCluster" + ] + } + }, + "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": "[extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', parameters('clusterName')), 'Microsoft.KubernetesConfiguration/extensions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the extension was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedCluster" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the managed cluster." + }, + "value": "[resourceId('Microsoft.ContainerService/managedClusters', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the managed cluster was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the managed cluster." + }, + "value": "[parameters('name')]" + }, + "controlPlaneFQDN": { + "type": "string", + "metadata": { + "description": "The control plane FQDN of the managed cluster." + }, + "value": "[if(parameters('enablePrivateCluster'), reference('managedCluster').privateFQDN, reference('managedCluster').fqdn)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('managedCluster', '2024-03-02-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "kubeletIdentityClientId": { + "type": "string", + "metadata": { + "description": "The Client ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'clientId'), '')]" + }, + "kubeletIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'objectId'), '')]" + }, + "kubeletIdentityResourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'resourceId'), '')]" + }, + "omsagentIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the OMS agent identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'omsagent'), 'identity'), 'objectId'), '')]" + }, + "keyvaultIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the Key Vault Secrets Provider identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'azureKeyvaultSecretsProvider'), 'identity'), 'objectId'), '')]" + }, + "keyvaultIdentityClientId": { + "type": "string", + "metadata": { + "description": "The Client ID of the Key Vault Secrets Provider identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'azureKeyvaultSecretsProvider'), 'identity'), 'clientId'), '')]" + }, + "ingressApplicationGatewayIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of Application Gateway Ingress Controller (AGIC) identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'ingressApplicationGateway'), 'identity'), 'objectId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedCluster', '2024-03-02-preview', 'full').location]" + }, + "oidcIssuerUrl": { + "type": "string", + "metadata": { + "description": "The OIDC token issuer URL." + }, + "value": "[coalesce(tryGet(tryGet(reference('managedCluster'), 'oidcIssuerProfile'), 'issuerURL'), '')]" + }, + "addonProfiles": { + "type": "object", + "metadata": { + "description": "The addonProfiles of the Kubernetes cluster." + }, + "value": "[coalesce(tryGet(reference('managedCluster'), 'addonProfiles'), createObject())]" + }, + "webAppRoutingIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of Web Application Routing." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'ingressProfile'), 'webAppRouting'), 'identity'), 'objectId'), '')]" + } + } + } + }, + "dependsOn": [ + "logAnalytics" + ] + }, + "containerRegistry": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-registry', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('containerRegistryName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "scopeMaps": { + "value": "[parameters('scopeMaps')]" + }, + "acrSku": { + "value": "[parameters('acrSku')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "diagnosticSettings": { + "value": [ + { + "logCategoriesAndGroups": [ + { + "category": "ContainerRegistryRepositoryEvents", + "enabled": true + }, + { + "category": "ContainerRegistryLoginEvents", + "enabled": true + } + ], + "workspaceResourceId": "[if(not(empty(parameters('logAnalyticsName'))), resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName')), '')]", + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "[parameters('containerRegistryRoleName')]", + "principalId": "[reference('managedCluster').outputs.kubeletIdentityObjectId.value]", + "roleDefinitionIdOrName": "[variables('acrPullRole')]" + } + ] + } + }, + "template": { + "$schema": "https://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": "8799580877381308457" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR).", + "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 + }, + "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", + "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 + }, + "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 + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "scopeMapsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "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." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registr is enabled or not. Default is enabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "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 networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "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." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "$ref": "#/definitions/scopeMapsType", + "metadata": { + "description": "Optional. Scope maps setting." + } + } + }, + "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": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "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')]" + } + }, + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{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" + } + } + } + } + }, + "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'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(not(empty(parameters('networkRuleSetIpRules'))), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', parameters('networkRuleSetIpRules')), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "registry_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.ContainerRegistry/registries/{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": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerRegistry/registries/{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": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', 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": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "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.29.47.4906", + "templateHash": "9144531012597082524" + }, + "name": "Container Registries scopeMaps", + "description": "This module deploys an Azure Container Registry (ACR) scopeMap.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), 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.29.47.4906", + "templateHash": "8531695368487734118" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "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." + } + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + } + }, + "template": { + "$schema": "https://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": "12196074162662855376" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set.", + "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." + } + } + } + }, + "authCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Required. The managed identity definition for this resource." + } + }, + "authCredentials": { + "$ref": "#/definitions/authCredentialsType", + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "variables": { + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]" + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2023-11-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[variables('identity')]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('credentialSet', '2023-11-01-preview', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name'), replace(replace(coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository, '/', '-'), '.', '-'))]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "4294329625336671928" + }, + "name": "Container Registries Cache", + "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be dereived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action'), createArray('chart_delete', 'chart_push', 'delete', 'push', 'quarantine'))]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), 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.29.47.4906", + "templateHash": "14912363209364245195" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "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." + } + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), 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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), 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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), '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'))]" + }, + "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": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2019-05-01').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('registry', '2023-06-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2023-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.systemAssignedMIPrincipalId.value]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.resourceId.value]" + } + } + } + } + }, + "dependsOn": [ + "logAnalytics", + "managedCluster" + ] + }, + "keyVault": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-key-vault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "accessPolicies": { + "value": [ + { + "objectId": "[reference('managedCluster').outputs.kubeletIdentityObjectId.value]", + "permissions": { + "secrets": [ + "get", + "list" + ] + } + } + ] + } + }, + "template": { + "$schema": "https://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": "6878673228466609441" + }, + "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": { + "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." + } + }, + "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": "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 (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.keyvault-vault.{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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "7494731697751039419" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "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.29.47.4906", + "templateHash": "4990258423482296566" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "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 + } + }, + "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": { + "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 (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')]" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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'))]" + }, + "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.29.47.4906", + "templateHash": "10436564794447478489" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "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 + } + }, + "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": { + "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 (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())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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": { + "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], '2020-06-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": [ + "managedCluster" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights components were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "managedClusterName": { + "type": "string", + "metadata": { + "description": "The resource name of the AKS cluster." + }, + "value": "[reference('managedCluster').outputs.name.value]" + }, + "managedClusterClientId": { + "type": "string", + "metadata": { + "description": "The Client ID of the AKS identity." + }, + "value": "[reference('managedCluster').outputs.kubeletIdentityClientId.value]" + }, + "managedClusterObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the AKS identity." + }, + "value": "[reference('managedCluster').outputs.kubeletIdentityObjectId.value]" + }, + "managedClusterResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the AKS cluster." + }, + "value": "[reference('managedCluster').outputs.kubeletIdentityResourceId.value]" + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The resource name of the ACR." + }, + "value": "[reference('containerRegistry').outputs.name.value]" + }, + "containerRegistryLoginServer": { + "type": "string", + "metadata": { + "description": "The login server for the container registry." + }, + "value": "[reference('containerRegistry').outputs.loginServer.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..9961f0c426 --- /dev/null +++ b/avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the App Service to create.') +param appName string + +@description('Required. The name of the App Service Plan to create.') +param appServicePlanName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: { + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + } +} + +resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { + name: appServicePlanName + location: location + sku: { + name: 'B3' + } + properties: { + reserved: true + } +} + +resource app 'Microsoft.Web/sites@2022-09-01' = { + name: appName + location: location + kind: 'app,linux' + properties: { + serverFarmId: appServicePlan.id + siteConfig: { + linuxFxVersion: 'dotnetcore|8.0' + alwaysOn: true + } + } + identity: { type: 'SystemAssigned' } +} + +@description('The app identity Principal Id.') +output identityPrincipalId string = app.identity.principalId + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.name diff --git a/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..0e40826546 --- /dev/null +++ b/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,63 @@ +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}-azd-aks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'paamin' + +@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' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-dependencies' + scope: resourceGroup + params: { + location: resourceLocation + appName: 'dep-${namePrefix}-app-${serviceShort}' + appServicePlanName: 'dep-${namePrefix}-apps-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${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: 'mc${uniqueString(deployment().name)}-${serviceShort}' + containerRegistryName: '${uniqueString(deployment().name, resourceLocation)}testcontainerregistry${serviceShort}' + logAnalyticsName: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + keyVaultName: 'kv${uniqueString(deployment().name)}-${serviceShort}' + location: resourceLocation + principalId: nestedDependencies.outputs.identityPrincipalId + } + } +] diff --git a/avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep b/avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..9961f0c426 --- /dev/null +++ b/avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the App Service to create.') +param appName string + +@description('Required. The name of the App Service Plan to create.') +param appServicePlanName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: { + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + } +} + +resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { + name: appServicePlanName + location: location + sku: { + name: 'B3' + } + properties: { + reserved: true + } +} + +resource app 'Microsoft.Web/sites@2022-09-01' = { + name: appName + location: location + kind: 'app,linux' + properties: { + serverFarmId: appServicePlan.id + siteConfig: { + linuxFxVersion: 'dotnetcore|8.0' + alwaysOn: true + } + } + identity: { type: 'SystemAssigned' } +} + +@description('The app identity Principal Id.') +output identityPrincipalId string = app.identity.principalId + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.name diff --git a/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep b/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..964c796fff --- /dev/null +++ b/avm/ptn/azd/aks/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}-azd-aks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'paamax' + +@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_#' + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param containerRegistryRoleName string = newGuid() + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param aksClusterRoleAssignmentName string = newGuid() + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-dependencies' + scope: resourceGroup + params: { + location: resourceLocation + appName: 'dep-${namePrefix}-app-${serviceShort}' + appServicePlanName: 'dep-${namePrefix}-apps-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${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: 'mc${uniqueString(deployment().name)}-${serviceShort}' + containerRegistryName: '${uniqueString(deployment().name, resourceLocation)}testcontainerregistry${serviceShort}' + skuTier: 'Free' + webApplicationRoutingEnabled: true + agentPools: [ + { + name: 'npuserpool' + mode: 'User' + osType: 'Linux' + maxPods: 30 + type: 'VirtualMachineScaleSets' + maxSurge: '33%' + vmSize: 'standard_a2' + } + ] + logAnalyticsName: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + keyVaultName: 'kv${uniqueString(deployment().name)}-${serviceShort}' + location: resourceLocation + principalId: nestedDependencies.outputs.identityPrincipalId + acrSku: 'Basic' + dnsPrefix: 'dep-${namePrefix}-dns-${serviceShort}' + principalType: 'ServicePrincipal' + containerRegistryRoleName: containerRegistryRoleName + aksClusterRoleAssignmentName: aksClusterRoleAssignmentName + } + } +] diff --git a/avm/ptn/azd/aks/version.json b/avm/ptn/azd/aks/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/aks/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From d863654c67f7e92f628a38901ee088579772c608 Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:32:04 +0200 Subject: [PATCH 67/93] fix: Cognitive services small update to trigger publishing (#3513) ## Description Small update to trigger publishing ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Feriqua%2Fcog-ser-pub)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/cognitive-services/account/README.md | 4 ++-- avm/res/cognitive-services/account/main.bicep | 2 +- avm/res/cognitive-services/account/main.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 9462bf4a9b..a2c4698c2e 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1646,7 +1646,7 @@ param tags = { | [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | bool | Restrict outbound network access. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | -| [`sku`](#parameter-sku) | string | SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | +| [`sku`](#parameter-sku) | string | SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`userOwnedStorage`](#parameter-userownedstorage) | array | The storage accounts for this resource. | @@ -2685,7 +2685,7 @@ The name for the accessKey2 secret to create. ### Parameter: `sku` -SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. +SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. - Required: No - Type: string diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 96147cc72d..8dbadcfb78 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -34,7 +34,7 @@ param name string ]) param kind string -@description('Optional. SKU of the Cognitive Services resource. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') @allowed([ 'C2' 'C3' diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 013a5b598c..b1c8468f51 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "9722036366573656954" + "templateHash": "4946778004284930976" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -694,7 +694,7 @@ "S9" ], "metadata": { - "description": "Optional. SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." } }, "location": { From b5ce0f2816e601df2b26b114ac161440a9a067f0 Mon Sep 17 00:00:00 2001 From: "Menghua Chen (MSFT)" <111940661+Menghua1@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:42:18 +0800 Subject: [PATCH 68/93] fix: Update the module identifiers in the issue template to the correct alphabetical order. (#3514) ## Description Fixes pipeline issue https://github.com/Azure/bicep-registry-modules/actions/runs/11288332565/job/31395906879. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-project](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg?branch=fix-pipeline-issue)](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f5002e3373..98b755c430 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,8 +17,8 @@ /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep -/avm/ptn/azd/ml-project/ @Azure/avm-ptn-azd-mlproject-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/ml-project/ @Azure/avm-ptn-azd-mlproject-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/monitoring/ @Azure/avm-ptn-azd-monitoring-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/dev-ops/cicd-agents-and-runners/ @Azure/avm-ptn-devops-cicdagentsandrunners-module-owners-bicep @Azure/avm-module-reviewers-bicep From fdfb2e6f1b44ba52fe38566353a0b2c9a60e0118 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 11 Oct 2024 13:49:59 +0200 Subject: [PATCH 69/93] fix: Container-Instace - Updated parameter type to be more specific (#3392) ## Description Updated DNS servers parameter to be a string array instead of just an array as it's the type in the API ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.container-instance.container-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=users%2Falsehr%2Fcontainer-app-version&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml) | --- avm/res/container-instance/container-group/main.bicep | 2 +- avm/res/container-instance/container-group/main.json | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/avm/res/container-instance/container-group/main.bicep b/avm/res/container-instance/container-group/main.bicep index 5e0dec8fcd..2baee0b1d1 100644 --- a/avm/res/container-instance/container-group/main.bicep +++ b/avm/res/container-instance/container-group/main.bicep @@ -49,7 +49,7 @@ param autoGeneratedDomainNameLabelScope string = 'TenantReuse' param dnsNameLabel string? @description('Optional. List of dns servers used by the containers for lookups.') -param dnsNameServers array? +param dnsNameServers string[]? @description('Optional. DNS search domain which will be appended to each DNS lookup.') param dnsSearchDomains string? diff --git a/avm/res/container-instance/container-group/main.json b/avm/res/container-instance/container-group/main.json index ad6b40f5e8..7b1c128ccd 100644 --- a/avm/res/container-instance/container-group/main.json +++ b/avm/res/container-instance/container-group/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "4541932168440754260" + "version": "0.30.23.60470", + "templateHash": "14261370383859328082" }, "name": "Container Instances Container Groups", "description": "This module deploys a Container Instance Container Group.", @@ -536,6 +536,9 @@ }, "dnsNameServers": { "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { "description": "Optional. List of dns servers used by the containers for lookups." From 0ef32a0de24db13e094f2024cb397853cf6bb62b Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 11 Oct 2024 20:56:07 +0200 Subject: [PATCH 70/93] feat: DevOpsPool - Fixed parameter requirement for images (#3401) ## Description - Fixed the requirement for the image parameter to allow the usage of a compute gallery image Example from portal deployment ![image](https://github.com/user-attachments/assets/d6a304eb-bc27-4d71-8411-cd62eeb42e2b) Exported JSON ```json "images": [ { "resourceId": "/Subscriptions/b765c5e5-ae60-4724-9b59-36fbcf56795b/Providers/Microsoft.Compute/Locations/westeurope/publishers/microsoftwindowsdesktop/artifacttypes/vmimage/offers/windows-11/skus/win11-22h2-pro/versions/latest", "buffer": "*" }, { "wellKnownImageName": "ubuntu-22.04/latest", "buffer": "*", "aliases": [ "ubuntu-22.04" ] }, { "resourceId": "/subscriptions/b765c5e5-ae60-4724-9b59-36fbcf56795b/resourceGroups/rg-ado-agents/providers/Microsoft.Compute/galleries/galaib/images/sid-linux/versions/latest", "buffer": "*" } ] ``` ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.dev-ops-infrastructure.pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml/badge.svg?branch=users%2Falsehr%2FdevopsPoolImageFix&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/res/dev-ops-infrastructure/pool/README.md | 24 ++-- .../dev-ops-infrastructure/pool/main.bicep | 24 +++- avm/res/dev-ops-infrastructure/pool/main.json | 123 ++++++++++++------ 3 files changed, 114 insertions(+), 57 deletions(-) diff --git a/avm/res/dev-ops-infrastructure/pool/README.md b/avm/res/dev-ops-infrastructure/pool/README.md index dee3ec1d9f..9896670d02 100644 --- a/avm/res/dev-ops-infrastructure/pool/README.md +++ b/avm/res/dev-ops-infrastructure/pool/README.md @@ -810,11 +810,12 @@ The VM images of the machines in the pool. - Required: Yes - Type: array -**Required parameters** +**Conditional parameters** | Parameter | Type | Description | | :-- | :-- | :-- | -| [`wellKnownImageName`](#parameter-imageswellknownimagename) | string | The image to use from a well-known set of images made available to customers. | +| [`resourceId`](#parameter-imagesresourceid) | string | The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set. | +| [`wellKnownImageName`](#parameter-imageswellknownimagename) | string | The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set. | **Optional parameters** @@ -822,13 +823,19 @@ The VM images of the machines in the pool. | :-- | :-- | :-- | | [`aliases`](#parameter-imagesaliases) | array | List of aliases to reference the image by. | | [`buffer`](#parameter-imagesbuffer) | string | The percentage of the buffer to be allocated to this image. | -| [`resourceId`](#parameter-imagesresourceid) | string | The resource id of the image. | + +### Parameter: `images.resourceId` + +The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set. + +- Required: No +- Type: string ### Parameter: `images.wellKnownImageName` -The image to use from a well-known set of images made available to customers. +The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set. -- Required: Yes +- Required: No - Type: string ### Parameter: `images.aliases` @@ -845,13 +852,6 @@ The percentage of the buffer to be allocated to this image. - Required: No - Type: string -### Parameter: `images.resourceId` - -The resource id of the image. - -- Required: No -- Type: string - ### Parameter: `name` Name of the pool. It needs to be globally unique. diff --git a/avm/res/dev-ops-infrastructure/pool/main.bicep b/avm/res/dev-ops-infrastructure/pool/main.bicep index af61e650fe..358dd0abf5 100644 --- a/avm/res/dev-ops-infrastructure/pool/main.bicep +++ b/avm/res/dev-ops-infrastructure/pool/main.bicep @@ -14,7 +14,7 @@ param fabricProfileSkuName string param concurrency int @description('Required. The VM images of the machines in the pool.') -param images imageType +param images imageType[] @description('Optional. The geo-location where the resource lives.') param location string = resourceGroup().location @@ -235,6 +235,7 @@ output location string = managedDevOpsPool.location @description('The principal ID of the system assigned identity.') output systemAssignedMIPrincipalId string? = managedDevOpsPool.?identity.?principalId +@export() type osProfileType = { @description('Required. The logon type of the machine.') logonType: ('Interactive' | 'Service') @@ -252,6 +253,7 @@ type osProfileType = { }? } +@export() type storageProfileType = { @description('Optional. The Azure SKU name of the machines in the pool.') osDiskStorageAccountType: ('Premium' | 'StandardSSD' | 'Standard')? @@ -272,6 +274,7 @@ type storageProfileType = { }[]? }? +@export() type imageType = { @description('Optional. List of aliases to reference the image by.') aliases: string[]? @@ -279,13 +282,14 @@ type imageType = { @description('Optional. The percentage of the buffer to be allocated to this image.') buffer: string? - @description('Required. The image to use from a well-known set of images made available to customers.') - wellKnownImageName: string + @description('Conditional. The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set.') + wellKnownImageName: string? - @description('Optional. The resource id of the image.') + @description('Conditional. The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set.') resourceId: string? -}[] +} +@export() type organizationProfileType = { @description('Required. Azure DevOps organization profile.') kind: 'AzureDevOps' @@ -317,6 +321,7 @@ type organizationProfileType = { }[] } +@export() type dataDiskType = { @description('Optional. The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/.') caching: ('None' | 'ReadOnly' | 'ReadWrite')? @@ -331,6 +336,7 @@ type dataDiskType = { storageAccountType: ('Premium_LRS' | 'Premium_ZRS' | 'StandardSSD_LRS' | 'StandardSSD_ZRS' | 'Standard_LRS')? }[]? +@export() type resourcePredictionsProfileAutomaticType = { @description('Required. The stand-by agent scheme is determined based on historical demand.') kind: 'Automatic' @@ -339,11 +345,13 @@ type resourcePredictionsProfileAutomaticType = { predictionPreference: 'Balanced' | 'MostCostEffective' | 'MoreCostEffective' | 'MorePerformance' | 'BestPerformance' } +@export() type resourcePredictionsProfileManualType = { @description('Required. Customer provides the stand-by agent scheme.') kind: 'Manual' } +@export() type agentStatefulType = { @description('Required. Stateful profile meaning that the machines will be returned to the pool after running a job.') kind: 'Stateful' @@ -362,6 +370,7 @@ type agentStatefulType = { resourcePredictionsProfile: (resourcePredictionsProfileAutomaticType | resourcePredictionsProfileManualType)? } +@export() type agentStatelessType = { @description('Required. Stateless profile meaning that the machines will be cleaned up after running a job.') kind: 'Stateless' @@ -400,8 +409,10 @@ type agentStatelessType = { } @discriminator('kind') +@export() type agentProfileType = agentStatefulType | agentStatelessType +@export() type roleAssignmentType = { @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') name: string? @@ -428,6 +439,7 @@ type roleAssignmentType = { delegatedManagedIdentityResourceId: string? }[]? +@export() type lockType = { @description('Optional. Specify the name of lock.') name: string? @@ -436,6 +448,7 @@ type lockType = { kind: ('CanNotDelete' | 'ReadOnly' | 'None')? }? +@export() type diagnosticSettingType = { @description('Optional. The name of diagnostic setting.') name: string? @@ -480,6 +493,7 @@ type diagnosticSettingType = { marketplacePartnerResourceId: string? }[]? +@export() type managedIdentitiesType = { @description('Optional. Enables system assigned managed identity on the resource.') systemAssigned: bool? diff --git a/avm/res/dev-ops-infrastructure/pool/main.json b/avm/res/dev-ops-infrastructure/pool/main.json index 689ef6eb8c..05c3db9232 100644 --- a/avm/res/dev-ops-infrastructure/pool/main.json +++ b/avm/res/dev-ops-infrastructure/pool/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "3502193398932835678" + "templateHash": "14560645908978883645" }, "name": "Managed DevOps Pool", "description": "This module deploys the Managed DevOps Pool resource.", @@ -57,6 +57,9 @@ "description": "Optional. The secret management settings of the machines in the pool." } } + }, + "metadata": { + "__bicep_export!": true } }, "storageProfileType": { @@ -127,44 +130,48 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "imageType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "aliases": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of aliases to reference the image by." - } - }, - "buffer": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The percentage of the buffer to be allocated to this image." - } - }, - "wellKnownImageName": { - "type": "string", - "metadata": { - "description": "Required. The image to use from a well-known set of images made available to customers." - } + "type": "object", + "properties": { + "aliases": { + "type": "array", + "items": { + "type": "string" }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the image." - } + "nullable": true, + "metadata": { + "description": "Optional. List of aliases to reference the image by." + } + }, + "buffer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The percentage of the buffer to be allocated to this image." + } + }, + "wellKnownImageName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set." } } + }, + "metadata": { + "__bicep_export!": true } }, "organizationProfileType": { @@ -255,6 +262,9 @@ "description": "Required. The list of Azure DevOps organizations the pool should be present in.." } } + }, + "metadata": { + "__bicep_export!": true } }, "dataDiskType": { @@ -304,7 +314,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "resourcePredictionsProfileAutomaticType": { "type": "object", @@ -331,6 +344,9 @@ "description": "Required. Determines the balance between cost and performance." } } + }, + "metadata": { + "__bicep_export!": true } }, "resourcePredictionsProfileManualType": { @@ -345,6 +361,9 @@ "description": "Required. Customer provides the stand-by agent scheme." } } + }, + "metadata": { + "__bicep_export!": true } }, "agentStatefulType": { @@ -396,6 +415,9 @@ "description": "Optional. Determines how the stand-by scheme should be provided." } } + }, + "metadata": { + "__bicep_export!": true } }, "agentStatelessType": { @@ -454,6 +476,9 @@ "description": "Optional. Determines how the stand-by scheme should be provided." } } + }, + "metadata": { + "__bicep_export!": true } }, "agentProfileType": { @@ -468,6 +493,9 @@ "$ref": "#/definitions/agentStatelessType" } } + }, + "metadata": { + "__bicep_export!": true } }, "roleAssignmentType": { @@ -541,7 +569,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "lockType": { "type": "object", @@ -566,7 +597,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "diagnosticSettingType": { "type": "array", @@ -686,7 +720,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "managedIdentitiesType": { "type": "object", @@ -709,7 +746,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } } }, "parameters": { @@ -734,7 +774,10 @@ } }, "images": { - "$ref": "#/definitions/imageType", + "type": "array", + "items": { + "$ref": "#/definitions/imageType" + }, "metadata": { "description": "Required. The VM images of the machines in the pool." } From 4b99f59014f613d924139ad8dface53e32e1f4a9 Mon Sep 17 00:00:00 2001 From: "Shihua Xiong (MSFT)" <138103031+NanaXiong00@users.noreply.github.com> Date: Sat, 12 Oct 2024 16:33:22 +0800 Subject: [PATCH 71/93] feat: Add new ptn modules `avm/ptn/azd/container-app-upsert` (#3260) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1222 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.container-app-upsert](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-app-upsert.yml/badge.svg?branch=ptn%2Fazd%2Fcontainer-app-upsert)](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-app-upsert.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.ptn.azd.container-app-upsert.yml | 88 + avm/ptn/azd/container-app-upsert/README.md | 616 +++++ avm/ptn/azd/container-app-upsert/main.bicep | 177 ++ avm/ptn/azd/container-app-upsert/main.json | 2179 +++++++++++++++++ .../tests/e2e/defaults/dependencies.bicep | 14 + .../tests/e2e/defaults/main.test.bicep | 58 + .../tests/e2e/max/dependencies.bicep | 120 + .../tests/e2e/max/main.test.bicep | 101 + avm/ptn/azd/container-app-upsert/version.json | 7 + 11 files changed, 3362 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.container-app-upsert.yml create mode 100644 avm/ptn/azd/container-app-upsert/README.md create mode 100644 avm/ptn/azd/container-app-upsert/main.bicep create mode 100644 avm/ptn/azd/container-app-upsert/main.json create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep create mode 100644 avm/ptn/azd/container-app-upsert/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 98b755c430..07a798c38d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,6 +15,7 @@ /avm/ptn/azd/acr-container-app/ @Azure/avm-ptn-azd-acrcontainerapp-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/aks/ @Azure/avm-ptn-azd-aks-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/container-app-upsert/ @Azure/avm-ptn-azd-containerappupsert-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 2d27f5792e..4fdaa41ac2 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -50,6 +50,7 @@ body: - "avm/ptn/azd/acr-container-app" - "avm/ptn/azd/aks" - "avm/ptn/azd/apim-api" + - "avm/ptn/azd/container-app-upsert" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - "avm/ptn/azd/ml-hub-dependencies" diff --git a/.github/workflows/avm.ptn.azd.container-app-upsert.yml b/.github/workflows/avm.ptn.azd.container-app-upsert.yml new file mode 100644 index 0000000000..a612a7c55c --- /dev/null +++ b/.github/workflows/avm.ptn.azd.container-app-upsert.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.container-app-upsert" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.container-app-upsert.yml" + - "avm/ptn/azd/container-app-upsert/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/container-app-upsert" + workflowPath: ".github/workflows/avm.ptn.azd.container-app-upsert.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/azd/container-app-upsert/README.md b/avm/ptn/azd/container-app-upsert/README.md new file mode 100644 index 0000000000..5caa1cec82 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/README.md @@ -0,0 +1,616 @@ +# Azd Container App Upsert `[Azd/ContainerAppUpsert]` + +Creates or updates an existing Azure Container App. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case + +## 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.App/containerApps` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2024-03-01/containerApps) | +| `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) | + +## 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/azd/container-app-upsert:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module containerAppUpsert 'br/public:avm/ptn/azd/container-app-upsert:' = { + name: 'containerAppUpsertDeployment' + params: { + // Required parameters + containerAppsEnvironmentName: '' + name: 'acaumin001' + // 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 + "containerAppsEnvironmentName": { + "value": "" + }, + "name": { + "value": "acaumin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/container-app-upsert:' + +// Required parameters +param containerAppsEnvironmentName = '' +param name = 'acaumin001' +// 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 containerAppUpsert 'br/public:avm/ptn/azd/container-app-upsert:' = { + name: 'containerAppUpsertDeployment' + params: { + // Required parameters + containerAppsEnvironmentName: '' + name: '' + // Non-required parameters + containerRegistryName: '' + daprEnabled: true + env: [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } + ] + exists: true + identityName: '' + identityPrincipalId: '' + identityType: 'UserAssigned' + location: '' + secrets: { + secureList: [ + { + name: 'containerappstoredsecret' + value: '' + } + { + identity: '' + keyVaultUrl: '' + name: 'keyvaultstoredsecret' + } + ] + } + tags: { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' + } + userAssignedIdentityResourceId: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "containerAppsEnvironmentName": { + "value": "" + }, + "name": { + "value": "" + }, + // Non-required parameters + "containerRegistryName": { + "value": "" + }, + "daprEnabled": { + "value": true + }, + "env": { + "value": [ + { + "name": "ContainerAppStoredSecretName", + "secretRef": "containerappstoredsecret" + }, + { + "name": "ContainerAppKeyVaultStoredSecretName", + "secretRef": "keyvaultstoredsecret" + } + ] + }, + "exists": { + "value": true + }, + "identityName": { + "value": "" + }, + "identityPrincipalId": { + "value": "" + }, + "identityType": { + "value": "UserAssigned" + }, + "location": { + "value": "" + }, + "secrets": { + "value": { + "secureList": [ + { + "name": "containerappstoredsecret", + "value": "" + }, + { + "identity": "", + "keyVaultUrl": "", + "name": "keyvaultstoredsecret" + } + ] + } + }, + "tags": { + "value": { + "Env": "test", + "hidden-title": "This is visible in the resource name" + } + }, + "userAssignedIdentityResourceId": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/container-app-upsert:' + +// Required parameters +param containerAppsEnvironmentName = '' +param name = '' +// Non-required parameters +param containerRegistryName = '' +param daprEnabled = true +param env = [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } +] +param exists = true +param identityName = '' +param identityPrincipalId = '' +param identityType = 'UserAssigned' +param location = '' +param secrets = { + secureList: [ + { + name: 'containerappstoredsecret' + value: '' + } + { + identity: '' + keyVaultUrl: '' + name: 'keyvaultstoredsecret' + } + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param userAssignedIdentityResourceId = '' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerAppsEnvironmentName`](#parameter-containerappsenvironmentname) | string | Name of the environment for container apps. | +| [`name`](#parameter-name) | string | The name of the Container App. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerCpuCoreCount`](#parameter-containercpucorecount) | string | The number of CPU cores allocated to a single container instance, e.g., 0.5. | +| [`containerMaxReplicas`](#parameter-containermaxreplicas) | int | The maximum number of replicas to run. Must be at least 1. | +| [`containerMemory`](#parameter-containermemory) | string | The amount of memory allocated to a single container instance, e.g., 1Gi. | +| [`containerMinReplicas`](#parameter-containerminreplicas) | int | The minimum number of replicas to run. Must be at least 2. | +| [`containerName`](#parameter-containername) | string | The name of the container. | +| [`containerRegistryHostSuffix`](#parameter-containerregistryhostsuffix) | string | Hostname suffix for container registry. Set when deploying to sovereign clouds. | +| [`containerRegistryName`](#parameter-containerregistryname) | string | The name of the container registry. | +| [`daprAppId`](#parameter-daprappid) | string | The Dapr app ID. | +| [`daprAppProtocol`](#parameter-daprappprotocol) | string | The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC. | +| [`daprEnabled`](#parameter-daprenabled) | bool | Enable or disable Dapr for the container app. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`env`](#parameter-env) | array | The environment variables for the container. | +| [`exists`](#parameter-exists) | bool | Specifies if the resource already exists. | +| [`external`](#parameter-external) | bool | Specifies if the resource ingress is exposed externally. | +| [`identityName`](#parameter-identityname) | string | The name of the user-assigned identity. | +| [`identityPrincipalId`](#parameter-identityprincipalid) | string | The principal ID of the principal to assign the role to. | +| [`identityType`](#parameter-identitytype) | string | The type of identity for the resource. | +| [`imageName`](#parameter-imagename) | string | The name of the container image. | +| [`ingressEnabled`](#parameter-ingressenabled) | bool | Specifies if Ingress is enabled for the container app. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`secrets`](#parameter-secrets) | secureObject | The secrets required for the container. | +| [`serviceBinds`](#parameter-servicebinds) | array | The service binds associated with the container. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`targetPort`](#parameter-targetport) | int | The target port for the container. | +| [`userAssignedIdentityResourceId`](#parameter-userassignedidentityresourceid) | string | The resource id of the user-assigned identity. | + +### Parameter: `containerAppsEnvironmentName` + +Name of the environment for container apps. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the Container App. + +- Required: Yes +- Type: string + +### Parameter: `containerCpuCoreCount` + +The number of CPU cores allocated to a single container instance, e.g., 0.5. + +- Required: No +- Type: string +- Default: `'0.5'` + +### Parameter: `containerMaxReplicas` + +The maximum number of replicas to run. Must be at least 1. + +- Required: No +- Type: int +- Default: `10` + +### Parameter: `containerMemory` + +The amount of memory allocated to a single container instance, e.g., 1Gi. + +- Required: No +- Type: string +- Default: `'1.0Gi'` + +### Parameter: `containerMinReplicas` + +The minimum number of replicas to run. Must be at least 2. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `containerName` + +The name of the container. + +- Required: No +- Type: string +- Default: `'main'` + +### Parameter: `containerRegistryHostSuffix` + +Hostname suffix for container registry. Set when deploying to sovereign clouds. + +- Required: No +- Type: string +- Default: `'azurecr.io'` + +### Parameter: `containerRegistryName` + +The name of the container registry. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `daprAppId` + +The Dapr app ID. + +- Required: No +- Type: string +- Default: `[parameters('containerName')]` + +### Parameter: `daprAppProtocol` + +The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC. + +- Required: No +- Type: string +- Default: `'http'` +- Allowed: + ```Bicep + [ + 'grpc' + 'http' + ] + ``` + +### Parameter: `daprEnabled` + +Enable or disable Dapr for the container app. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `env` + +The environment variables for the container. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-envname) | string | Environment variable name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`secretRef`](#parameter-envsecretref) | string | Name of the Container App secret from which to pull the environment variable value. | +| [`value`](#parameter-envvalue) | string | Non-secret environment variable value. | + +### Parameter: `env.name` + +Environment variable name. + +- Required: Yes +- Type: string + +### Parameter: `env.secretRef` + +Name of the Container App secret from which to pull the environment variable value. + +- Required: No +- Type: string + +### Parameter: `env.value` + +Non-secret environment variable value. + +- Required: No +- Type: string + +### Parameter: `exists` + +Specifies if the resource already exists. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `external` + +Specifies if the resource ingress is exposed externally. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `identityName` + +The name of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `identityPrincipalId` + +The principal ID of the principal to assign the role to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `identityType` + +The type of identity for the resource. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'None' + 'SystemAssigned' + 'UserAssigned' + ] + ``` + +### Parameter: `imageName` + +The name of the container image. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ingressEnabled` + +Specifies if Ingress is enabled for the container app. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `secrets` + +The secrets required for the container. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `serviceBinds` + +The service binds associated with the container. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `targetPort` + +The target port for the container. + +- Required: No +- Type: int +- Default: `80` + +### Parameter: `userAssignedIdentityResourceId` + +The resource id of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `defaultDomain` | string | The Default domain of the Container App. | +| `imageName` | string | The name of the container image. | +| `name` | string | The name of the Container App. | +| `resourceGroupName` | string | The name of the resource group the Container App was deployed into. | +| `resourceId` | string | The resource ID of the Container App. | +| `uri` | string | The uri of the Container App. | + +## 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/ptn/azd/acr-container-app:0.1.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/ptn/azd/container-app-upsert/main.bicep b/avm/ptn/azd/container-app-upsert/main.bicep new file mode 100644 index 0000000000..17533fdf52 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/main.bicep @@ -0,0 +1,177 @@ +metadata name = 'Azd Container App Upsert' +metadata description = '''Creates or updates an existing Azure Container App. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the Container App.') +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. Name of the environment for container apps.') +param containerAppsEnvironmentName string + +@description('Optional. The number of CPU cores allocated to a single container instance, e.g., 0.5.') +param containerCpuCoreCount string = '0.5' + +@description('Optional. The maximum number of replicas to run. Must be at least 1.') +@minValue(1) +param containerMaxReplicas int = 10 + +@description('Optional. The amount of memory allocated to a single container instance, e.g., 1Gi.') +param containerMemory string = '1.0Gi' + +@description('Optional. The minimum number of replicas to run. Must be at least 2.') +@minValue(1) +param containerMinReplicas int = 2 + +@description('Optional. The name of the container.') +param containerName string = 'main' + +@description('Optional. The name of the container registry.') +param containerRegistryName string = '' + +@description('Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds.') +param containerRegistryHostSuffix string = 'azurecr.io' + +@allowed(['http', 'grpc']) +@description('Optional. The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC.') +param daprAppProtocol string = 'http' + +@description('Optional. Enable or disable Dapr for the container app.') +param daprEnabled bool = false + +@description('Optional. The Dapr app ID.') +param daprAppId string = containerName + +@description('Optional. Specifies if the resource already exists.') +param exists bool = false + +@description('Optional. Specifies if Ingress is enabled for the container app.') +param ingressEnabled bool = true + +@description('Optional. The type of identity for the resource.') +@allowed(['None', 'SystemAssigned', 'UserAssigned']) +param identityType string = 'None' + +@description('Optional. The name of the user-assigned identity.') +param identityName string = '' + +@description('Optional. The name of the container image.') +param imageName string = '' + +@description('Optional. The secrets required for the container.') +@secure() +param secrets object = {} + +@description('Optional. The environment variables for the container.') +param env environmentType[]? + +@description('Optional. Specifies if the resource ingress is exposed externally.') +param external bool = true + +@description('Optional. The service binds associated with the container.') +param serviceBinds array = [] + +@description('Optional. The target port for the container.') +param targetPort int = 80 + +@description('Optional. The principal ID of the principal to assign the role to.') +param identityPrincipalId string = '' + +@description('Optional. The resource id of the user-assigned identity.') +param userAssignedIdentityResourceId string = '' + +@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.azd-containerappupsert.${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 existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { + name: name +} + +module app 'br/public:avm/ptn/azd/acr-container-app:0.1.0' = { + name: '${uniqueString(deployment().name, location)}-container-app-update' + params: { + name: name + location: location + tags: tags + identityType: identityType + identityName: identityName + ingressEnabled: ingressEnabled + containerName: containerName + containerAppsEnvironmentName: containerAppsEnvironmentName + containerRegistryName: containerRegistryName + containerRegistryHostSuffix: containerRegistryHostSuffix + containerCpuCoreCount: containerCpuCoreCount + containerMemory: containerMemory + containerMinReplicas: containerMinReplicas + containerMaxReplicas: containerMaxReplicas + daprEnabled: daprEnabled + daprAppId: daprAppId + daprAppProtocol: daprAppProtocol + secrets: secrets + external: external + env: env + imageName: !empty(imageName) ? imageName : exists ? existingApp.properties.template.containers[0].image : '' + targetPort: targetPort + serviceBinds: serviceBinds + principalId: !empty(identityName) && !empty(containerRegistryName) ? identityPrincipalId : '' + userAssignedIdentityResourceId: !empty(identityName) && !empty(containerRegistryName) + ? userAssignedIdentityResourceId + : '' + enableTelemetry: enableTelemetry + } +} + +@description('The Default domain of the Container App.') +output defaultDomain string = app.outputs.defaultDomain + +@description('The name of the container image.') +output imageName string = app.outputs.imageName + +@description('The name of the Container App.') +output name string = app.outputs.name + +@description('The uri of the Container App.') +output uri string = app.outputs.uri + +@description('The resource ID of the Container App.') +output resourceId string = app.outputs.resourceId + +@description('The name of the resource group the Container App was deployed into.') +output resourceGroupName string = resourceGroup().name + +type environmentType = { + @description('Required. Environment variable name.') + name: string + + @description('Optional. Name of the Container App secret from which to pull the environment variable value.') + secretRef: string? + + @description('Optional. Non-secret environment variable value.') + value: string? +} diff --git a/avm/ptn/azd/container-app-upsert/main.json b/avm/ptn/azd/container-app-upsert/main.json new file mode 100644 index 0000000000..087916758f --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/main.json @@ -0,0 +1,2179 @@ +{ + "$schema": "https://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": "610733373146441190" + }, + "name": "Azd Container App Upsert", + "description": "Creates or updates an existing Azure Container App.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "environmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Container App." + } + }, + "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." + } + }, + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "Required. Name of the environment for container apps." + } + }, + "containerCpuCoreCount": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. The number of CPU cores allocated to a single container instance, e.g., 0.5." + } + }, + "containerMaxReplicas": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. The maximum number of replicas to run. Must be at least 1." + } + }, + "containerMemory": { + "type": "string", + "defaultValue": "1.0Gi", + "metadata": { + "description": "Optional. The amount of memory allocated to a single container instance, e.g., 1Gi." + } + }, + "containerMinReplicas": { + "type": "int", + "defaultValue": 2, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of replicas to run. Must be at least 2." + } + }, + "containerName": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "Optional. The name of the container." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container registry." + } + }, + "containerRegistryHostSuffix": { + "type": "string", + "defaultValue": "azurecr.io", + "metadata": { + "description": "Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds." + } + }, + "daprAppProtocol": { + "type": "string", + "defaultValue": "http", + "allowedValues": [ + "http", + "grpc" + ], + "metadata": { + "description": "Optional. The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC." + } + }, + "daprEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable or disable Dapr for the container app." + } + }, + "daprAppId": { + "type": "string", + "defaultValue": "[parameters('containerName')]", + "metadata": { + "description": "Optional. The Dapr app ID." + } + }, + "exists": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the resource already exists." + } + }, + "ingressEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if Ingress is enabled for the container app." + } + }, + "identityType": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "SystemAssigned", + "UserAssigned" + ], + "metadata": { + "description": "Optional. The type of identity for the resource." + } + }, + "identityName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the user-assigned identity." + } + }, + "imageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container image." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets required for the container." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables for the container." + } + }, + "external": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the resource ingress is exposed externally." + } + }, + "serviceBinds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service binds associated with the container." + } + }, + "targetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. The target port for the container." + } + }, + "identityPrincipalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The principal ID of the principal to assign the role to." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource id of the user-assigned identity." + } + }, + "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.ptn.azd-containerappupsert.{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" + } + } + } + } + }, + "existingApp": { + "condition": "[parameters('exists')]", + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2023-05-02-preview", + "name": "[parameters('name')]" + }, + "app": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-app-update', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "identityType": { + "value": "[parameters('identityType')]" + }, + "identityName": { + "value": "[parameters('identityName')]" + }, + "ingressEnabled": { + "value": "[parameters('ingressEnabled')]" + }, + "containerName": { + "value": "[parameters('containerName')]" + }, + "containerAppsEnvironmentName": { + "value": "[parameters('containerAppsEnvironmentName')]" + }, + "containerRegistryName": { + "value": "[parameters('containerRegistryName')]" + }, + "containerRegistryHostSuffix": { + "value": "[parameters('containerRegistryHostSuffix')]" + }, + "containerCpuCoreCount": { + "value": "[parameters('containerCpuCoreCount')]" + }, + "containerMemory": { + "value": "[parameters('containerMemory')]" + }, + "containerMinReplicas": { + "value": "[parameters('containerMinReplicas')]" + }, + "containerMaxReplicas": { + "value": "[parameters('containerMaxReplicas')]" + }, + "daprEnabled": { + "value": "[parameters('daprEnabled')]" + }, + "daprAppId": { + "value": "[parameters('daprAppId')]" + }, + "daprAppProtocol": { + "value": "[parameters('daprAppProtocol')]" + }, + "secrets": { + "value": "[parameters('secrets')]" + }, + "external": { + "value": "[parameters('external')]" + }, + "env": { + "value": "[parameters('env')]" + }, + "imageName": "[if(not(empty(parameters('imageName'))), createObject('value', parameters('imageName')), if(parameters('exists'), createObject('value', reference('existingApp').template.containers[0].image), createObject('value', '')))]", + "targetPort": { + "value": "[parameters('targetPort')]" + }, + "serviceBinds": { + "value": "[parameters('serviceBinds')]" + }, + "principalId": "[if(and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName')))), createObject('value', parameters('identityPrincipalId')), createObject('value', ''))]", + "userAssignedIdentityResourceId": "[if(and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName')))), createObject('value', parameters('userAssignedIdentityResourceId')), createObject('value', ''))]", + "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": "1832494856594008897" + }, + "name": "Azd ACR Linked Container App", + "description": "Creates a container app in an Azure Container App environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "environmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Container App." + } + }, + "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." + } + }, + "allowedOrigins": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Allowed origins." + } + }, + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "Required. Name of the environment for container apps." + } + }, + "containerCpuCoreCount": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. CPU cores allocated to a single container instance, e.g., 0.5." + } + }, + "containerMaxReplicas": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. The maximum number of replicas to run. Must be at least 1." + } + }, + "containerMemory": { + "type": "string", + "defaultValue": "1.0Gi", + "metadata": { + "description": "Optional. Memory allocated to a single container instance, e.g., 1Gi." + } + }, + "containerMinReplicas": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The minimum number of replicas to run. Must be at least 2." + } + }, + "containerName": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "Optional. The name of the container." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container registry." + } + }, + "containerRegistryHostSuffix": { + "type": "string", + "defaultValue": "azurecr.io", + "metadata": { + "description": "Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds." + } + }, + "daprAppProtocol": { + "type": "string", + "defaultValue": "http", + "allowedValues": [ + "http", + "grpc" + ], + "metadata": { + "description": "Optional. The protocol used by Dapr to connect to the app, e.g., http or grpc." + } + }, + "daprAppId": { + "type": "string", + "defaultValue": "[parameters('containerName')]", + "metadata": { + "description": "Optional. The Dapr app ID." + } + }, + "daprEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable Dapr." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables for the container." + } + }, + "external": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the resource ingress is exposed externally." + } + }, + "identityName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the user-assigned identity." + } + }, + "identityType": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "SystemAssigned", + "UserAssigned" + ], + "metadata": { + "description": "Optional. The type of identity for the resource." + } + }, + "imageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container image." + } + }, + "ingressEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if Ingress is enabled for the container app." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "revisionMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets required for the container." + } + }, + "serviceBinds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service binds associated with the container." + } + }, + "serviceType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container apps add-on to use. e.g. redis." + } + }, + "targetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. The target port for the container." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "principalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The principal ID of the principal to assign the role to." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource id of the user-assigned identity." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "usePrivateRegistry": "[and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName'))))]", + "normalizedIdentityType": "[if(not(empty(parameters('identityName'))), 'UserAssigned', parameters('identityType'))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-acrcontainerapp.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "containerAppsEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2023-05-01", + "name": "[parameters('containerAppsEnvironmentName')]" + }, + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-app', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": "[if(and(not(empty(parameters('identityName'))), equals(variables('normalizedIdentityType'), 'UserAssigned')), createObject('value', createObject('userAssignedResourceIds', createArray(parameters('userAssignedIdentityResourceId')))), createObject('value', createObject('systemAssigned', equals(variables('normalizedIdentityType'), 'SystemAssigned'))))]", + "environmentResourceId": { + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('containerAppsEnvironmentName'))]" + }, + "activeRevisionsMode": { + "value": "[parameters('revisionMode')]" + }, + "disableIngress": { + "value": "[not(parameters('ingressEnabled'))]" + }, + "ingressExternal": { + "value": "[parameters('external')]" + }, + "ingressTargetPort": { + "value": "[parameters('targetPort')]" + }, + "ingressTransport": { + "value": "[parameters('ingressTransport')]" + }, + "ipSecurityRestrictions": { + "value": "[parameters('ipSecurityRestrictions')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": { + "value": { + "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" + } + }, + "dapr": "[if(parameters('daprEnabled'), createObject('value', createObject('enabled', true(), 'appId', parameters('daprAppId'), 'appProtocol', parameters('daprAppProtocol'), 'appPort', if(parameters('ingressEnabled'), parameters('targetPort'), 0))), createObject('value', createObject('enabled', false())))]", + "secrets": { + "value": "[parameters('secrets')]" + }, + "includeAddOns": { + "value": "[parameters('includeAddOns')]" + }, + "service": { + "value": { + "type": "[parameters('serviceType')]" + } + }, + "registries": "[if(variables('usePrivateRegistry'), createObject('value', createArray(createObject('server', format('{0}.{1}', parameters('containerRegistryName'), parameters('containerRegistryHostSuffix')), 'identity', parameters('userAssignedIdentityResourceId')))), createObject('value', createArray()))]", + "serviceBinds": { + "value": "[parameters('serviceBinds')]" + }, + "containers": { + "value": [ + { + "image": "[if(not(empty(parameters('imageName'))), parameters('imageName'), 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest')]", + "name": "[parameters('containerName')]", + "env": "[parameters('env')]", + "resources": { + "cpu": "[json(parameters('containerCpuCoreCount'))]", + "memory": "[parameters('containerMemory')]" + } + } + ] + }, + "scaleMaxReplicas": { + "value": "[parameters('containerMaxReplicas')]" + }, + "scaleMinReplicas": { + "value": "[parameters('containerMinReplicas')]" + }, + "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.29.47.4906", + "templateHash": "9894768173968934379" + }, + "name": "Container Apps", + "description": "This module deploys a Container App.", + "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 + }, + "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 + }, + "container": { + "type": "object", + "properties": { + "args": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command arguments." + } + }, + "command": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVar" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container environment variables." + } + }, + "image": { + "type": "string", + "metadata": { + "description": "Required. Container image tag." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Custom container name." + } + }, + "probes": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbe" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of probes for the container." + } + }, + "resources": { + "type": "object", + "metadata": { + "description": "Required. Container resource requirements." + } + }, + "volumeMounts": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeMount" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container volume mounts." + } + } + } + }, + "ingressPortMapping": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + } + }, + "serviceBind": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + } + }, + "environmentVar": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + }, + "containerAppProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGet", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocket", + "nullable": true, + "metadata": { + "description": "Optional. TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "nullable": true + }, + "containerAppProbeHttpGet": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItem" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + } + }, + "containerAppProbeHttpGetHeadersItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + } + }, + "containerAppProbeTcpSocket": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + } + }, + "volumeMount": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dev ContainerApp service type." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMapping" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": 10, + "metadata": { + "description": "Optional. Maximum number of container replicas. Defaults to 10 if not set." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "Optional. Minimum number of container replicas. Defaults to 3 if not set." + } + }, + "scaleRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Scaling rules." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBind" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "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." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this 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." + } + }, + "customDomains": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom domain bindings for Container App hostnames." + } + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "trafficLabel": { + "type": "string", + "defaultValue": "label-1", + "metadata": { + "description": "Optional. Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes." + } + }, + "trafficLatestRevision": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates that the traffic weight belongs to a latest stable revision." + } + }, + "trafficRevisionName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of a revision." + } + }, + "trafficWeight": { + "type": "int", + "defaultValue": 100, + "metadata": { + "description": "Optional. Traffic weight assigned to a revision." + } + }, + "dapr": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dapr configuration for the Container App." + } + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/container" + }, + "metadata": { + "description": "Required. List of container definitions for the Container App." + } + }, + "initContainersTemplate": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of specialized containers that run before app containers." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of volume definitions for the Container App." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + } + }, + "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)))))]" + } + ], + "secretList": "[if(not(empty(parameters('secrets'))), parameters('secrets').secureList, createArray())]", + "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": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.10.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" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[if(not(empty(parameters('dapr'))), parameters('dapr'), null())]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', if(not(empty(parameters('customDomains'))), parameters('customDomains'), null()), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', if(not(empty(parameters('ipSecurityRestrictions'))), parameters('ipSecurityRestrictions'), null()), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), createArray(createObject('label', parameters('trafficLabel'), 'latestRevision', parameters('trafficLatestRevision'), 'revisionName', parameters('trafficRevisionName'), 'weight', parameters('trafficWeight'))), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(and(parameters('includeAddOns'), not(empty(parameters('service')))), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[if(not(empty(parameters('registries'))), parameters('registries'), null())]", + "secrets": "[variables('secretList')]" + }, + "template": { + "containers": "[parameters('containers')]", + "initContainers": "[if(not(empty(parameters('initContainersTemplate'))), parameters('initContainersTemplate'), null())]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": { + "maxReplicas": "[parameters('scaleMaxReplicas')]", + "minReplicas": "[parameters('scaleMinReplicas')]", + "rules": "[if(not(empty(parameters('scaleRules'))), parameters('scaleRules'), null())]" + }, + "serviceBinds": "[if(and(parameters('includeAddOns'), not(empty(parameters('serviceBinds')))), parameters('serviceBinds'), null())]", + "volumes": "[if(not(empty(parameters('volumes'))), parameters('volumes'), null())]" + }, + "workloadProfileName": "[parameters('workloadProfileName')]" + } + }, + "containerApp_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.App/containerApps/{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": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.App/containerApps/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', 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": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('containerApp', '2024-03-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2024-03-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "containerAppsEnvironment", + "containerRegistryAccess" + ] + }, + "containerRegistryAccess": { + "condition": "[variables('usePrivateRegistry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-access', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerRegistryName": { + "value": "[parameters('containerRegistryName')]" + }, + "principalId": "[if(variables('usePrivateRegistry'), createObject('value', parameters('principalId')), createObject('value', ''))]", + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "11140098273900072819" + }, + "name": "ACR Pull permissions", + "description": "Assigns ACR Pull permissions to access an Azure Container Registry.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the container registry." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "acrPullRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "acrpullrole-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[parameters('principalId')]" + }, + "resourceId": { + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]" + }, + "roleDefinitionId": { + "value": "[variables('acrPullRole')]" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "1847432691715853168" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource.", + "owner": "Azure/module-maintainers" + }, + "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('0.1.1', '.', '-'), 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]" + } + } + } + } + } + ] + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('containerAppsEnvironment').defaultDomain]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the identity." + }, + "value": "[if(equals(variables('normalizedIdentityType'), 'None'), '', if(empty(parameters('identityName')), reference('containerApp').outputs.systemAssignedMIPrincipalId.value, parameters('principalId')))]" + }, + "imageName": { + "type": "string", + "metadata": { + "description": "The name of the container image." + }, + "value": "[parameters('imageName')]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "serviceBind": { + "type": "object", + "metadata": { + "description": "The service binds associated with the container." + }, + "value": "[if(not(empty(parameters('serviceType'))), createObject('serviceId', reference('containerApp').outputs.resourceId.value, 'name', reference('containerApp').outputs.name.value), createObject())]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the Container App." + }, + "value": "[if(parameters('ingressEnabled'), format('https://{0}', reference('containerApp').outputs.fqdn.value), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "existingApp" + ] + } + }, + "outputs": { + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Container App." + }, + "value": "[reference('app').outputs.defaultDomain.value]" + }, + "imageName": { + "type": "string", + "metadata": { + "description": "The name of the container image." + }, + "value": "[reference('app').outputs.imageName.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[reference('app').outputs.name.value]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the Container App." + }, + "value": "[reference('app').outputs.uri.value]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[reference('app').outputs.resourceId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..6c93d0689b --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,14 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: {} +} + +@description('The name of the Container Apps environment.') +output containerAppsEnvironmentName string = managedEnvironment.name diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..e991a50a79 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/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}-azd-containerappupsert-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acaumin' + +@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 + managedEnvironmentName: 'dep-${namePrefix}-me-${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' + containerAppsEnvironmentName: nestedDependencies.outputs.containerAppsEnvironmentName + location: resourceLocation + } + } +] diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..a1bb685580 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep @@ -0,0 +1,120 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault referenced by the Container Apps.') +param keyVaultName string + +@description('Required. The secret name of the Key Vault referenced by the Container Apps.') +param keyVaultSecretName string + +@description('Optional. Key vault stored secret to pass into environment variables. The value is a GUID.') +@secure() +param myCustomKeyVaultSecret string = newGuid() + +@description('Required. The name of the Container App.') +param containerAppName string + +@description('Required. The name of the Container Registry.') +param containerRegistryName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: {} +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: subscription().tenantId + publicNetworkAccess: 'Enabled' + enableRbacAuthorization: true + } +} + +resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { + parent: keyVault + name: keyVaultSecretName + properties: { + value: myCustomKeyVaultSecret + } +} + +@description('The the built-in Key Vault Secret User role definition.') +resource roleDefinitionKeyVault 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + scope: subscription() + name: '4633458b-17de-408a-b874-0445c86b69e6' +} + +resource roleAssignmentKeyVault 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, managedIdentity.id) + scope: keyVault + properties: { + roleDefinitionId: roleDefinitionKeyVault.id + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +module containerApp 'br/public:avm/res/app/container-app:0.9.0' = { + name: containerAppName + params: { + name: containerAppName + containers: [ + { + name: 'simple-hello-world-container' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { + // workaround as 'float' values are not supported in Bicep, yet the resource providers expects them. Related issue: https://github.com/Azure/bicep/issues/1386 + cpu: json('0.25') + memory: '0.5Gi' + } + } + ] + environmentResourceId: managedEnvironment.id + } +} + +module containerRegistry 'br/public:avm/res/container-registry/registry:0.5.1' = { + name: containerRegistryName + params: { + name: containerRegistryName + } +} + +@description('The name of the Container Apps environment.') +output containerAppsEnvironmentName string = managedEnvironment.name + +@description('The resource id of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The name of the created managed identity.') +output managedIdentityName string = managedIdentity.name + +@description('The principalId of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The key vault secret URI.') +output keyVaultSecretURI string = keyVaultSecret.properties.secretUri + +@description('The name of the Container Apps environment.') +output existingcontainerAppName string = containerApp.outputs.name + +@description('The Name of the Azure container registry.') +output containerRegistryName string = containerRegistry.outputs.name diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..bc27f38b58 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep @@ -0,0 +1,101 @@ +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}-azd-containerappupsert-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acaumax' + +@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_#' + +@description('Optional. Container app stored secret to pass into environment variables. The value is a GUID.') +@secure() +param myCustomContainerAppSecret string = newGuid() + +// ============ // +// 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 + managedEnvironmentName: 'dep-${namePrefix}-me-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + keyVaultSecretName: 'dep-${namePrefix}-kv-secret-${serviceShort}' + containerAppName: 'dep-${namePrefix}-ca-${serviceShort}' + containerRegistryName: 'dep${namePrefix}cr${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: nestedDependencies.outputs.existingcontainerAppName + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' + } + containerAppsEnvironmentName: nestedDependencies.outputs.containerAppsEnvironmentName + location: resourceLocation + identityType: 'UserAssigned' + identityName: nestedDependencies.outputs.managedIdentityName + containerRegistryName: nestedDependencies.outputs.containerRegistryName + identityPrincipalId: nestedDependencies.outputs.managedIdentityPrincipalId + userAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId + daprEnabled: true + secrets: { + secureList: [ + { + name: 'containerappstoredsecret' + value: myCustomContainerAppSecret + } + { + name: 'keyvaultstoredsecret' + keyVaultUrl: nestedDependencies.outputs.keyVaultSecretURI + identity: nestedDependencies.outputs.managedIdentityResourceId + } + ] + } + env: [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } + ] + exists: true + } + } +] diff --git a/avm/ptn/azd/container-app-upsert/version.json b/avm/ptn/azd/container-app-upsert/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 456d2bd5d9b63bcbd66205342bfe15e1a4fa1270 Mon Sep 17 00:00:00 2001 From: "Jianing Wang (MSFT)" <141212663+jianingwang123@users.noreply.github.com> Date: Sun, 13 Oct 2024 02:31:37 +0800 Subject: [PATCH 72/93] feat: Add the creation of `Microsoft.KeyVault/vaults/secrets` in Sql Server Module - `avm/res/sql/server` (#2859) ## Description Fixes #2608 Set `azure/login@v2` to use federated credential. (Due to some security policies, we are currently unable to use client secret for azure login. After completing all changes to this PR, we will restore the login method. This is currently only for testing the github pipeline.) ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.sql.server](https://github.com/jianingwang123/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=fix%2F2608)](https://github.com/jianingwang123/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio - for notification. --------- Co-authored-by: zedy --- avm/res/sql/server/README.md | 169 ++++++++++- avm/res/sql/server/main.bicep | 55 ++++ avm/res/sql/server/main.json | 262 ++++++++++++++++-- .../sql/server/modules/keyVaultExport.bicep | 62 +++++ .../tests/e2e/kvSecrets/dependencies.bicep | 21 ++ .../tests/e2e/kvSecrets/main.test.bicep | 73 +++++ 6 files changed, 606 insertions(+), 36 deletions(-) create mode 100644 avm/res/sql/server/modules/keyVaultExport.bicep create mode 100644 avm/res/sql/server/tests/e2e/kvSecrets/dependencies.bicep create mode 100644 avm/res/sql/server/tests/e2e/kvSecrets/main.test.bicep diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index e38347c937..92be8ea923 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -19,6 +19,7 @@ This module deploys an Azure SQL Server. | `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.Sql/servers` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/servers) | @@ -45,10 +46,11 @@ The following section provides usage examples for the module, which were used to - [With an administrator](#example-1-with-an-administrator) - [With audit settings](#example-2-with-audit-settings) - [Using only defaults](#example-3-using-only-defaults) -- [Using large parameter set](#example-4-using-large-parameter-set) -- [With a secondary database](#example-5-with-a-secondary-database) -- [With vulnerability assessment](#example-6-with-vulnerability-assessment) -- [WAF-aligned](#example-7-waf-aligned) +- [Deploying with a key vault reference to save secrets](#example-4-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-5-using-large-parameter-set) +- [With a secondary database](#example-6-with-a-secondary-database) +- [With vulnerability assessment](#example-7-with-vulnerability-assessment) +- [WAF-aligned](#example-8-waf-aligned) ### Example 1: _With an administrator_ @@ -310,7 +312,115 @@ param location = ''

  • -### Example 4: _Using large parameter set_ +### Example 4: _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 server 'br/public:avm/res/sql/server:' = { + name: 'serverDeployment' + params: { + // Required parameters + name: 'sqlkvs001' + // Non-required parameters + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + databases: [ + { + name: 'myDatabase' + } + ] + location: '' + secretsExportConfiguration: { + keyVaultResourceId: '' + sqlAdminPasswordSecretName: 'adminLoginPasswordKey' + sqlAzureConnectionStringSercretName: 'sqlConnectionStringKey' + } + } +} +``` + +
    +

    + +

    + +via 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": "sqlkvs001" + }, + // Non-required parameters + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "databases": { + "value": [ + { + "name": "myDatabase" + } + ] + }, + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "keyVaultResourceId": "", + "sqlAdminPasswordSecretName": "adminLoginPasswordKey", + "sqlAzureConnectionStringSercretName": "sqlConnectionStringKey" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlkvs001' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param databases = [ + { + name: 'myDatabase' + } +] +param location = '' +param secretsExportConfiguration = { + keyVaultResourceId: '' + sqlAdminPasswordSecretName: 'adminLoginPasswordKey' + sqlAzureConnectionStringSercretName: 'sqlConnectionStringKey' +} +``` + +
    +

    + +### Example 5: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -833,7 +943,7 @@ param vulnerabilityAssessmentsObj = {

    -### Example 5: _With a secondary database_ +### Example 6: _With a secondary database_ This instance deploys the module with a secondary database. @@ -956,7 +1066,7 @@ param tags = {

    -### Example 6: _With vulnerability assessment_ +### Example 7: _With vulnerability assessment_ This instance deploys the module with a vulnerability assessment. @@ -1133,7 +1243,7 @@ param vulnerabilityAssessmentsObj = {

    -### Example 7: _WAF-aligned_ +### Example 8: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1579,6 +1689,7 @@ param vulnerabilityAssessmentsObj = { | [`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 neither firewall rules nor virtual network rules are set. | | [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | string | Whether or not to restrict outbound network access for this server. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | | [`securityAlertPolicies`](#parameter-securityalertpolicies) | array | The security alert policies to create in the server. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`virtualNetworkRules`](#parameter-virtualnetworkrules) | array | The virtual network rules to create in the server. | @@ -2411,6 +2522,47 @@ The principal type of the assigned principal ID. ] ``` +### 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 resource ID of the key vault where to store the secrets of this module. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`sqlAdminPasswordSecretName`](#parameter-secretsexportconfigurationsqladminpasswordsecretname) | string | The sqlAdminPassword secret name to create. | +| [`sqlAzureConnectionStringSercretName`](#parameter-secretsexportconfigurationsqlazureconnectionstringsercretname) | string | The sqlAzureConnectionString secret name to create. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The resource ID of the key vault where to store the secrets of this module. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.sqlAdminPasswordSecretName` + +The sqlAdminPassword secret name to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.sqlAzureConnectionStringSercretName` + +The sqlAzureConnectionString secret name to create. + +- Required: No +- Type: string + ### Parameter: `securityAlertPolicies` The security alert policies to create in the server. @@ -2446,6 +2598,7 @@ The vulnerability assessment configuration. | 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 SQL server. | | `privateEndpoints` | array | The private endpoints of the SQL server. | diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep index e628668146..6a3921b4eb 100644 --- a/avm/res/sql/server/main.bicep +++ b/avm/res/sql/server/main.bicep @@ -105,6 +105,9 @@ param vulnerabilityAssessmentsObj object = {} @description('Optional. The audit settings configuration.') param auditSettings auditSettingsType? +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -491,6 +494,36 @@ module server_audit_settings 'audit-settings/main.bicep' = if (!empty(auditSetti } } +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!, 'sqlAdminPasswordSecretName') + ? [ + { + name: secretsExportConfiguration!.sqlAdminPasswordSecretName + value: administratorLoginPassword + } + ] + : [], + contains(secretsExportConfiguration!, 'sqlAzureConnectionStringSercretName') + ? [ + { + name: secretsExportConfiguration!.sqlAzureConnectionStringSercretName + value: 'Server=${server.properties.fullyQualifiedDomainName}; Database=${!empty(databases) ? databases[0].name : ''}; User=${administratorLogin}; Password=${administratorLoginPassword}' + } + ] + : [] + ) + } +} + @description('The name of the deployed SQL server.') output name string = server.name @@ -506,6 +539,11 @@ output systemAssignedMIPrincipalId string = server.?identity.?principalId ?? '' @description('The location the resource was deployed into.') output location string = server.location +@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) + : {} + @description('The private endpoints of the SQL server.') output privateEndpoints array = [ for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { @@ -681,3 +719,20 @@ type auditSettingsType = { @description('Optional. Specifies the identifier key of the auditing storage account.') storageAccountResourceId: string? } + +type secretsExportConfigurationType = { + @description('Required. The resource ID of the key vault where to store the secrets of this module.') + keyVaultResourceId: string + + @description('Optional. The sqlAdminPassword secret name to create.') + sqlAdminPasswordSecretName: string? + + @description('Optional. The sqlAzureConnectionString secret name to create.') + sqlAzureConnectionStringSercretName: string? +}? + +import { secretSetType } from 'modules/keyVaultExport.bicep' +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json index b13a78c08f..af15b03a96 100644 --- a/avm/res/sql/server/main.json +++ b/avm/res/sql/server/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13031224188572751832" + "version": "0.30.23.60470", + "templateHash": "779644860652942835" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", @@ -434,6 +434,64 @@ } } } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the key vault where to store the secrets of this module." + } + }, + "sqlAdminPasswordSecretName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The sqlAdminPassword secret name to create." + } + }, + "sqlAzureConnectionStringSercretName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The sqlAzureConnectionString secret name to create." + } + } + }, + "nullable": true + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "secretSetType": { + "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." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } } }, "parameters": { @@ -614,6 +672,13 @@ "metadata": { "description": "Optional. The audit settings configuration." } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } } }, "variables": { @@ -780,8 +845,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6019999815954957727" + "version": "0.30.23.60470", + "templateHash": "11407307502843440892" }, "name": "SQL Server Database", "description": "This module deploys an Azure SQL Server Database.", @@ -1258,8 +1323,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8635162595153731245" + "version": "0.30.23.60470", + "templateHash": "10836519140305169908" }, "name": "Azure SQL Server Database Short Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Short-Term Backup Retention Policy.", @@ -1360,8 +1425,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2778016138108001251" + "version": "0.30.23.60470", + "templateHash": "10064519186693398262" }, "name": "SQL Server Database Long Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Long-Term Backup Retention Policy.", @@ -1538,8 +1603,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18037703368269722870" + "version": "0.30.23.60470", + "templateHash": "1486548652639885128" }, "name": "SQL Server Elastic Pool", "description": "This module deploys an Azure SQL Server Elastic Pool.", @@ -2520,8 +2585,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7779473510493338097" + "version": "0.30.23.60470", + "templateHash": "6449556555046717103" }, "name": "Azure SQL Server Firewall Rule", "description": "This module deploys an Azure SQL Server Firewall Rule.", @@ -2626,8 +2691,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7859066741604114060" + "version": "0.30.23.60470", + "templateHash": "4969955763304077350" }, "name": "Azure SQL Server Virtual Network Rules", "description": "This module deploys an Azure SQL Server Virtual Network Rule.", @@ -2734,8 +2799,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6025191760768766090" + "version": "0.30.23.60470", + "templateHash": "15406914222375641032" }, "name": "Azure SQL Server Security Alert Policies", "description": "This module deploys an Azure SQL Server Security Alert Policy.", @@ -2885,8 +2950,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5682596516926040129" + "version": "0.30.23.60470", + "templateHash": "11004049200994426011" }, "name": "Azure SQL Server Vulnerability Assessments", "description": "This module deploys an Azure SQL Server Vulnerability Assessment.", @@ -2988,8 +3053,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17251889896692066430" + "version": "0.30.23.60470", + "templateHash": "13956215614091387428" } }, "parameters": { @@ -3077,8 +3142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5863771213375512760" + "version": "0.30.23.60470", + "templateHash": "17839617504395216689" }, "name": "Azure SQL Server Keys", "description": "This module deploys an Azure SQL Server Key.", @@ -3196,8 +3261,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6914924378490463775" + "version": "0.30.23.60470", + "templateHash": "11473914706327458055" }, "name": "Azure SQL Server Encryption Protector", "description": "This module deploys an Azure SQL Server Encryption Protector.", @@ -3329,8 +3394,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4165841300638093382" + "version": "0.30.23.60470", + "templateHash": "2456263707393734456" }, "name": "Azure SQL Server Audit Settings", "description": "This module deploys an Azure SQL Server Audit Settings.", @@ -3468,8 +3533,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17251889896692066430" + "version": "0.30.23.60470", + "templateHash": "13956215614091387428" } }, "parameters": { @@ -3528,6 +3593,140 @@ "dependsOn": [ "server" ] + }, + "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'), 'sqlAdminPasswordSecretName'), createArray(createObject('name', parameters('secretsExportConfiguration').sqlAdminPasswordSecretName, 'value', parameters('administratorLoginPassword'))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'sqlAzureConnectionStringSercretName'), createArray(createObject('name', parameters('secretsExportConfiguration').sqlAzureConnectionStringSercretName, 'value', format('Server={0}; Database={1}; User={2}; Password={3}', reference('server').fullyQualifiedDomainName, if(not(empty(parameters('databases'))), parameters('databases')[0].name, ''), parameters('administratorLogin'), parameters('administratorLoginPassword')))), 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.30.23.60470", + "templateHash": "16142913599202614386" + } + }, + "definitions": { + "secretSetType": { + "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." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "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." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets 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]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "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]" + } + } + } + } + } + }, + "dependsOn": [ + "server" + ] } }, "outputs": { @@ -3566,6 +3765,13 @@ }, "value": "[reference('server', '2023-08-01-preview', 'full').location]" }, + "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())]" + }, "privateEndpoints": { "type": "array", "metadata": { diff --git a/avm/res/sql/server/modules/keyVaultExport.bicep b/avm/res/sql/server/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..c4ff7c2f9d --- /dev/null +++ b/avm/res/sql/server/modules/keyVaultExport.bicep @@ -0,0 +1,62 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the secrets in.') +param keyVaultName string + +@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 // +// =========== // + +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetType[] = [ + #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 + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string +} + +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} diff --git a/avm/res/sql/server/tests/e2e/kvSecrets/dependencies.bicep b/avm/res/sql/server/tests/e2e/kvSecrets/dependencies.bicep new file mode 100644 index 0000000000..2d7a1701e3 --- /dev/null +++ b/avm/res/sql/server/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 keyVault 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 + enableRbacAuthorization: true + } +} + +@description('The id of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/sql/server/tests/e2e/kvSecrets/main.test.bicep b/avm/res/sql/server/tests/e2e/kvSecrets/main.test.bicep new file mode 100644 index 0000000000..31e94ee0a9 --- /dev/null +++ b/avm/res/sql/server/tests/e2e/kvSecrets/main.test.bicep @@ -0,0 +1,73 @@ +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}-sql.servers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sqlkvs' + +@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: { + 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' + location: resourceLocation + administratorLogin: 'adminUserName' + administratorLoginPassword: password + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + sqlAdminPasswordSecretName: 'adminLoginPasswordKey' + sqlAzureConnectionStringSercretName: 'sqlConnectionStringKey' + } + databases: [ + { + name: 'myDatabase' + } + ] + } + } +] From 016b72753ef1ef3352d134a6d0fa4e754922a505 Mon Sep 17 00:00:00 2001 From: Richard Hooper Date: Sat, 12 Oct 2024 22:38:03 +0200 Subject: [PATCH 73/93] feat: fix ps rule error for waf aligned aks - `avm/res/container-service/managed-cluster` (#3228) ## Description Fixes issue with ps rule for WAF. For some reason it still complains about default, But I don't think the ps rule should be running on the default test as it is not required. I am unsure how to change that. Happy to do so with some guidance. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.container-service.managed-cluster](https://github.com/PixelRobots/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml/badge.svg?branch=fix-ps-rule-error-aks-rh)](https://github.com/PixelRobots/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Signed-off-by: PixelRobots <22979170+PixelRobots@users.noreply.github.com> Co-authored-by: Alexander Sehr Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../managed-cluster/README.md | 348 +++++++++++++++--- .../managed-cluster/main.bicep | 34 +- .../managed-cluster/main.json | 70 +++- .../tests/e2e/automatic/main.test.bicep | 31 +- .../tests/e2e/azure/main.test.bicep | 33 ++ .../tests/e2e/waf-aligned/main.test.bicep | 33 ++ .../managed-cluster/version.json | 2 +- .../psrule/.ps-rule/min-suppress.Rule.yaml | 2 + 8 files changed, 461 insertions(+), 92 deletions(-) diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md index 3b68c8346d..b5cbcf20e7 100644 --- a/avm/res/container-service/managed-cluster/README.md +++ b/avm/res/container-service/managed-cluster/README.md @@ -64,23 +64,26 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' - maintenanceConfiguration: { - maintenanceWindow: { - durationHours: 4 - schedule: { - absoluteMonthly: '' - daily: '' - relativeMonthly: '' - weekly: { - dayOfWeek: 'Sunday' - intervalWeeks: 1 + maintenanceConfigurations: [ + { + maintenanceWindow: { + durationHours: 4 + schedule: { + absoluteMonthly: '' + daily: '' + relativeMonthly: '' + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } } + startDate: '2024-07-03' + startTime: '00:00' + utcOffset: '+00:00' } - startDate: '2024-07-03' - startTime: '00:00' - utcOffset: '+00:00' + name: 'aksManagedAutoUpgradeSchedule' } - } + ] managedIdentities: { systemAssigned: true } @@ -118,24 +121,27 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" }, - "maintenanceConfiguration": { - "value": { - "maintenanceWindow": { - "durationHours": 4, - "schedule": { - "absoluteMonthly": "", - "daily": "", - "relativeMonthly": "", - "weekly": { - "dayOfWeek": "Sunday", - "intervalWeeks": 1 - } + "maintenanceConfigurations": { + "value": [ + { + "maintenanceWindow": { + "durationHours": 4, + "schedule": { + "absoluteMonthly": "", + "daily": "", + "relativeMonthly": "", + "weekly": { + "dayOfWeek": "Sunday", + "intervalWeeks": 1 + } + }, + "startDate": "2024-07-03", + "startTime": "00:00", + "utcOffset": "+00:00" }, - "startDate": "2024-07-03", - "startTime": "00:00", - "utcOffset": "+00:00" + "name": "aksManagedAutoUpgradeSchedule" } - } + ] }, "managedIdentities": { "value": { @@ -168,23 +174,26 @@ param primaryAgentPoolProfile = [ ] // Non-required parameters param location = '' -param maintenanceConfiguration = { - maintenanceWindow: { - durationHours: 4 - schedule: { - absoluteMonthly: '' - daily: '' - relativeMonthly: '' - weekly: { - dayOfWeek: 'Sunday' - intervalWeeks: 1 +param maintenanceConfigurations = [ + { + maintenanceWindow: { + durationHours: 4 + schedule: { + absoluteMonthly: '' + daily: '' + relativeMonthly: '' + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } } + startDate: '2024-07-03' + startTime: '00:00' + utcOffset: '+00:00' } - startDate: '2024-07-03' - startTime: '00:00' - utcOffset: '+00:00' + name: 'aksManagedAutoUpgradeSchedule' } -} +] param managedIdentities = { systemAssigned: true } @@ -276,6 +285,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' } ] + autoNodeOsUpgradeProfileUpgradeChannel: 'Unmanaged' autoUpgradeProfileUpgradeChannel: 'stable' customerManagedKey: { keyName: '' @@ -375,6 +385,38 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' @@ -502,6 +544,9 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' } ] +param autoNodeOsUpgradeProfileUpgradeChannel = 'Unmanaged' param autoUpgradeProfileUpgradeChannel = 'stable' param customerManagedKey = { keyName: '' @@ -873,6 +953,38 @@ param lock = { kind: 'CanNotDelete' name: 'myCustomLockName' } +param maintenanceConfigurations = [ + { + maintenanceWindow: { + durationHours: 4 + schedule: { + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-15' + startTime: '00:00' + utcOffset: '+00:00' + } + name: 'aksManagedAutoUpgradeSchedule' + } + { + maintenanceWindow: { + durationHours: 4 + schedule: { + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-15' + startTime: '00:00' + utcOffset: '+00:00' + } + name: 'aksManagedNodeOSUpgradeSchedule' + } +] param managedIdentities = { userAssignedResourcesIds: [ '' @@ -1806,6 +1918,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + maintenanceConfigurations: [ + { + maintenanceWindow: { + durationHours: 4 + schedule: { + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-15' + startTime: '00:00' + utcOffset: '+00:00' + } + name: 'aksManagedAutoUpgradeSchedule' + } + { + maintenanceWindow: { + durationHours: 4 + schedule: { + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-15' + startTime: '00:00' + utcOffset: '+00:00' + } + name: 'aksManagedNodeOSUpgradeSchedule' + } + ] managedIdentities: { userAssignedResourcesIds: [ '' @@ -1949,6 +2094,9 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" }, + "maintenanceConfigurations": { + "value": [ + { + "maintenanceWindow": { + "durationHours": 4, + "schedule": { + "weekly": { + "dayOfWeek": "Sunday", + "intervalWeeks": 1 + } + }, + "startDate": "2024-07-15", + "startTime": "00:00", + "utcOffset": "+00:00" + }, + "name": "aksManagedAutoUpgradeSchedule" + }, + { + "maintenanceWindow": { + "durationHours": 4, + "schedule": { + "weekly": { + "dayOfWeek": "Sunday", + "intervalWeeks": 1 + } + }, + "startDate": "2024-07-15", + "startTime": "00:00", + "utcOffset": "+00:00" + }, + "name": "aksManagedNodeOSUpgradeSchedule" + } + ] + }, "managedIdentities": { "value": { "userAssignedResourcesIds": [ @@ -2116,6 +2298,7 @@ param agentPools = [ vmSize: 'Standard_DS2_v2' } ] +param autoNodeOsUpgradeProfileUpgradeChannel = 'Unmanaged' param autoUpgradeProfileUpgradeChannel = 'stable' param diagnosticSettings = [ { @@ -2150,6 +2333,38 @@ param dnsServiceIP = '10.10.200.10' param enableAzureDefender = true param enablePrivateCluster = true param location = '' +param maintenanceConfigurations = [ + { + maintenanceWindow: { + durationHours: 4 + schedule: { + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-15' + startTime: '00:00' + utcOffset: '+00:00' + } + name: 'aksManagedAutoUpgradeSchedule' + } + { + maintenanceWindow: { + durationHours: 4 + schedule: { + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-15' + startTime: '00:00' + utcOffset: '+00:00' + } + name: 'aksManagedNodeOSUpgradeSchedule' + } +] param managedIdentities = { userAssignedResourcesIds: [ '' @@ -2203,6 +2418,7 @@ param tags = { | [`adminUsername`](#parameter-adminusername) | string | Specifies the administrator username of Linux virtual machines. | | [`agentPools`](#parameter-agentpools) | array | Define one or more secondary/additional agent pools. | | [`authorizedIPRanges`](#parameter-authorizedipranges) | array | IP ranges are specified in CIDR format, e.g. 137.117.106.88/29. This feature is not compatible with clusters that use Public IP Per Node, or clusters that are using a Basic Load Balancer. | +| [`autoNodeOsUpgradeProfileUpgradeChannel`](#parameter-autonodeosupgradeprofileupgradechannel) | string | Auto-upgrade channel on the Node Os. | | [`autoScalerProfileBalanceSimilarNodeGroups`](#parameter-autoscalerprofilebalancesimilarnodegroups) | bool | Specifies the balance of similar node groups for the auto-scaler of the AKS cluster. | | [`autoScalerProfileExpander`](#parameter-autoscalerprofileexpander) | string | Specifies the expand strategy for the auto-scaler of the AKS cluster. | | [`autoScalerProfileMaxEmptyBulkDelete`](#parameter-autoscalerprofilemaxemptybulkdelete) | string | Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster. | @@ -2265,7 +2481,7 @@ param tags = { | [`loadBalancerSku`](#parameter-loadbalancersku) | string | Specifies the sku of the load balancer used by the virtual machine scale sets used by nodepools. | | [`location`](#parameter-location) | string | Specifies the location of AKS cluster. It picks up Resource Group's location by default. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | -| [`maintenanceConfiguration`](#parameter-maintenanceconfiguration) | object | Whether or not to use AKS Automatic mode. | +| [`maintenanceConfigurations`](#parameter-maintenanceconfigurations) | array | Maintenance Window for Cluster auto upgrade and node OS upgrade. | | [`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. | | [`managedOutboundIPCount`](#parameter-managedoutboundipcount) | int | Outbound IP Count for the Load balancer. | | [`metricAnnotationsAllowList`](#parameter-metricannotationsallowlist) | string | A comma-separated list of Kubernetes cluster metrics annotations. | @@ -2765,6 +2981,23 @@ IP ranges are specified in CIDR format, e.g. 137.117.106.88/29. This feature is - Required: No - Type: array +### Parameter: `autoNodeOsUpgradeProfileUpgradeChannel` + +Auto-upgrade channel on the Node Os. + +- Required: No +- Type: string +- Default: `'Unmanaged'` +- Allowed: + ```Bicep + [ + 'NodeImage' + 'None' + 'SecurityPatch' + 'Unmanaged' + ] + ``` + ### Parameter: `autoScalerProfileBalanceSimilarNodeGroups` Specifies the balance of similar node groups for the auto-scaler of the AKS cluster. @@ -3588,26 +3821,41 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `maintenanceConfiguration` +### Parameter: `maintenanceConfigurations` -Whether or not to use AKS Automatic mode. +Maintenance Window for Cluster auto upgrade and node OS upgrade. - Required: No -- Type: object +- Type: array **Required parameters** | Parameter | Type | Description | | :-- | :-- | :-- | -| [`maintenanceWindow`](#parameter-maintenanceconfigurationmaintenancewindow) | object | Maintenance window for the maintenance configuration. | +| [`maintenanceWindow`](#parameter-maintenanceconfigurationsmaintenancewindow) | object | Maintenance window for the maintenance configuration. | +| [`name`](#parameter-maintenanceconfigurationsname) | string | Name of maintenance window. | -### Parameter: `maintenanceConfiguration.maintenanceWindow` +### Parameter: `maintenanceConfigurations.maintenanceWindow` Maintenance window for the maintenance configuration. - Required: Yes - Type: object +### Parameter: `maintenanceConfigurations.name` + +Name of maintenance window. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'aksManagedAutoUpgradeSchedule' + 'aksManagedNodeOSUpgradeSchedule' + ] + ``` + ### Parameter: `managedIdentities` The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. diff --git a/avm/res/container-service/managed-cluster/main.bicep b/avm/res/container-service/managed-cluster/main.bicep index 8fe68cc164..555b07cab8 100644 --- a/avm/res/container-service/managed-cluster/main.bicep +++ b/avm/res/container-service/managed-cluster/main.bicep @@ -156,8 +156,8 @@ param primaryAgentPoolProfile array @description('Optional. Define one or more secondary/additional agent pools.') param agentPools agentPoolType -@description('Optional. Whether or not to use AKS Automatic mode.') -param maintenanceConfiguration maintenanceConfigurationType +@description('Optional. Maintenance Window for Cluster auto upgrade and node OS upgrade.') +param maintenanceConfigurations maintenanceConfigurationType @description('Optional. Specifies whether the cost analysis add-on is enabled or not. If Enabled `enableStorageProfileDiskCSIDriver` is set to true as it is needed.') param costAnalysisEnabled bool = false @@ -270,6 +270,15 @@ param autoScalerProfileSkipNodesWithSystemPods bool = true @description('Optional. Auto-upgrade channel on the AKS cluster.') param autoUpgradeProfileUpgradeChannel string = 'stable' +@allowed([ + 'NodeImage' + 'None' + 'SecurityPatch' + 'Unmanaged' +]) +@description('Optional. Auto-upgrade channel on the Node Os.') +param autoNodeOsUpgradeProfileUpgradeChannel string = 'Unmanaged' + @description('Optional. Running in Kubenet is disabled by default due to the security related nature of AAD Pod Identity and the risks of IP spoofing.') param podIdentityProfileAllowNetworkPluginKubenet bool = false @@ -684,6 +693,7 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p } autoUpgradeProfile: { upgradeChannel: autoUpgradeProfileUpgradeChannel + nodeOSUpgradeChannel: autoNodeOsUpgradeProfileUpgradeChannel } apiServerAccessProfile: { authorizedIPRanges: authorizedIPRanges @@ -757,13 +767,16 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p } } -module managedCluster_maintenanceConfigurations 'maintenance-configurations/main.bicep' = if (!empty(maintenanceConfiguration)) { - name: '${uniqueString(deployment().name, location)}-ManagedCluster-MaintenanceConfigurations' - params: { - maintenanceWindow: maintenanceConfiguration!.maintenanceWindow - managedClusterName: managedCluster.name +module managedCluster_maintenanceConfigurations 'maintenance-configurations/main.bicep' = [ + for (maintenanceConfiguration, index) in (maintenanceConfigurations ?? []): if (!empty(maintenanceConfiguration)) { + name: '${uniqueString(deployment().name, location)}-ManagedCluster-MaintenanceConfigurations-${index}' + params: { + name: maintenanceConfiguration!.name + maintenanceWindow: maintenanceConfiguration!.maintenanceWindow + managedClusterName: managedCluster.name + } } -} +] module managedCluster_agentPools 'agent-pool/main.bicep' = [ for (agentPool, index) in (agentPools ?? []): { @@ -1202,6 +1215,9 @@ type customerManagedKeyType = { }? type maintenanceConfigurationType = { + @description('Required. Name of maintenance window.') + name: ('aksManagedAutoUpgradeSchedule' | 'aksManagedNodeOSUpgradeSchedule') + @description('Required. Maintenance window for the maintenance configuration.') maintenanceWindow: object -}? +}[]? diff --git a/avm/res/container-service/managed-cluster/main.json b/avm/res/container-service/managed-cluster/main.json index 5e11783720..142cc567ba 100644 --- a/avm/res/container-service/managed-cluster/main.json +++ b/avm/res/container-service/managed-cluster/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6707709888421096485" + "version": "0.30.23.60470", + "templateHash": "13565722664676041295" }, "name": "Azure Kubernetes Service (AKS) Managed Clusters", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster.", @@ -671,12 +671,25 @@ "nullable": true }, "maintenanceConfigurationType": { - "type": "object", - "properties": { - "maintenanceWindow": { - "type": "object", - "metadata": { - "description": "Required. Maintenance window for the maintenance configuration." + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "aksManagedAutoUpgradeSchedule", + "aksManagedNodeOSUpgradeSchedule" + ], + "metadata": { + "description": "Required. Name of maintenance window." + } + }, + "maintenanceWindow": { + "type": "object", + "metadata": { + "description": "Required. Maintenance window for the maintenance configuration." + } } } }, @@ -985,10 +998,10 @@ "description": "Optional. Define one or more secondary/additional agent pools." } }, - "maintenanceConfiguration": { + "maintenanceConfigurations": { "$ref": "#/definitions/maintenanceConfigurationType", "metadata": { - "description": "Optional. Whether or not to use AKS Automatic mode." + "description": "Optional. Maintenance Window for Cluster auto upgrade and node OS upgrade." } }, "costAnalysisEnabled": { @@ -1228,6 +1241,19 @@ "description": "Optional. Auto-upgrade channel on the AKS cluster." } }, + "autoNodeOsUpgradeProfileUpgradeChannel": { + "type": "string", + "defaultValue": "Unmanaged", + "allowedValues": [ + "NodeImage", + "None", + "SecurityPatch", + "Unmanaged" + ], + "metadata": { + "description": "Optional. Auto-upgrade channel on the Node Os." + } + }, "podIdentityProfileAllowNetworkPluginKubenet": { "type": "bool", "defaultValue": false, @@ -1676,7 +1702,8 @@ "skip-nodes-with-system-pods": "[toLower(string(parameters('autoScalerProfileSkipNodesWithSystemPods')))]" }, "autoUpgradeProfile": { - "upgradeChannel": "[parameters('autoUpgradeProfileUpgradeChannel')]" + "upgradeChannel": "[parameters('autoUpgradeProfileUpgradeChannel')]", + "nodeOSUpgradeChannel": "[parameters('autoNodeOsUpgradeProfileUpgradeChannel')]" }, "apiServerAccessProfile": { "authorizedIPRanges": "[parameters('authorizedIPRanges')]", @@ -1818,18 +1845,25 @@ ] }, "managedCluster_maintenanceConfigurations": { - "condition": "[not(empty(parameters('maintenanceConfiguration')))]", + "copy": { + "name": "managedCluster_maintenanceConfigurations", + "count": "[length(coalesce(parameters('maintenanceConfigurations'), createArray()))]" + }, + "condition": "[not(empty(coalesce(parameters('maintenanceConfigurations'), createArray())[copyIndex()]))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-ManagedCluster-MaintenanceConfigurations', uniqueString(deployment().name, parameters('location')))]", + "name": "[format('{0}-ManagedCluster-MaintenanceConfigurations-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(parameters('maintenanceConfigurations'), createArray())[copyIndex()].name]" + }, "maintenanceWindow": { - "value": "[parameters('maintenanceConfiguration').maintenanceWindow]" + "value": "[coalesce(parameters('maintenanceConfigurations'), createArray())[copyIndex()].maintenanceWindow]" }, "managedClusterName": { "value": "[parameters('name')]" @@ -1841,8 +1875,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12168542117744033419" + "version": "0.30.23.60470", + "templateHash": "2505380725266419010" }, "name": "Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations.", @@ -2038,8 +2072,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2004205618690542488" + "version": "0.30.23.60470", + "templateHash": "4315564225725874539" }, "name": "Azure Kubernetes Service (AKS) Managed Cluster Agent Pools", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Agent Pool.", diff --git a/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep index 5d8d63a837..cd20ff76e7 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep @@ -39,23 +39,26 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: resourceLocation - maintenanceConfiguration: { - maintenanceWindow: { - schedule: { - daily: null - weekly: { - intervalWeeks: 1 - dayOfWeek: 'Sunday' + maintenanceConfigurations: [ + { + name: 'aksManagedAutoUpgradeSchedule' + maintenanceWindow: { + schedule: { + daily: null + weekly: { + intervalWeeks: 1 + dayOfWeek: 'Sunday' + } + absoluteMonthly: null + relativeMonthly: null } - absoluteMonthly: null - relativeMonthly: null + durationHours: 4 + utcOffset: '+00:00' + startDate: '2024-07-03' + startTime: '00:00' } - durationHours: 4 - utcOffset: '+00:00' - startDate: '2024-07-03' - startTime: '00:00' } - } + ] managedIdentities: { systemAssigned: true } diff --git a/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep index 9032ea2840..76e6c50044 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep @@ -144,6 +144,39 @@ module testDeployment '../../../main.bicep' = [ } ] autoUpgradeProfileUpgradeChannel: 'stable' + autoNodeOsUpgradeProfileUpgradeChannel: 'Unmanaged' + maintenanceConfigurations: [ + { + name: 'aksManagedAutoUpgradeSchedule' + maintenanceWindow: { + schedule: { + weekly: { + intervalWeeks: 1 + dayOfWeek: 'Sunday' + } + } + durationHours: 4 + utcOffset: '+00:00' + startDate: '2024-07-15' + startTime: '00:00' + } + } + { + name: 'aksManagedNodeOSUpgradeSchedule' + maintenanceWindow: { + schedule: { + weekly: { + intervalWeeks: 1 + dayOfWeek: 'Sunday' + } + } + durationHours: 4 + utcOffset: '+00:00' + startDate: '2024-07-15' + startTime: '00:00' + } + } + ] enableWorkloadIdentity: true enableOidcIssuerProfile: true networkPlugin: 'azure' diff --git a/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep index fb5bf064bd..bb0487a6a1 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep @@ -139,6 +139,39 @@ module testDeployment '../../../main.bicep' = [ } ] autoUpgradeProfileUpgradeChannel: 'stable' + autoNodeOsUpgradeProfileUpgradeChannel: 'Unmanaged' + maintenanceConfigurations: [ + { + name: 'aksManagedAutoUpgradeSchedule' + maintenanceWindow: { + schedule: { + weekly: { + intervalWeeks: 1 + dayOfWeek: 'Sunday' + } + } + durationHours: 4 + utcOffset: '+00:00' + startDate: '2024-07-15' + startTime: '00:00' + } + } + { + name: 'aksManagedNodeOSUpgradeSchedule' + maintenanceWindow: { + schedule: { + weekly: { + intervalWeeks: 1 + dayOfWeek: 'Sunday' + } + } + durationHours: 4 + utcOffset: '+00:00' + startDate: '2024-07-15' + startTime: '00:00' + } + } + ] networkPlugin: 'azure' networkPolicy: 'azure' skuTier: 'Standard' diff --git a/avm/res/container-service/managed-cluster/version.json b/avm/res/container-service/managed-cluster/version.json index 76049e1c4a..13669e6601 100644 --- a/avm/res/container-service/managed-cluster/version.json +++ b/avm/res/container-service/managed-cluster/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.4", "pathFilters": [ "./main.json" ] diff --git a/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml b/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml index 603250a1e1..363fc837d3 100644 --- a/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml +++ b/avm/utilities/pipelines/staticValidation/psrule/.ps-rule/min-suppress.Rule.yaml @@ -46,6 +46,8 @@ spec: # Azure API Management - Azure.APIM.MultiRegion # Team agreed this is too expensive for most use cases and is safe to ignore. Would require dependencies for a min deployment. - Azure.APIM.ManagedIdentity + # AKS specific + - Azure.AKS.MaintenanceWindow # Excluded as it requires user input if: name: "." contains: From 341743c0d237743210eb843d7e9467cf41ba9080 Mon Sep 17 00:00:00 2001 From: Peter Budai Date: Sun, 13 Oct 2024 11:40:08 +0200 Subject: [PATCH 74/93] feat: Update SQL Server API - `avm/res/sql/server` (#3325) * Add support for enabling IPv6 in SQL server * Update allowed values for publicNetworkAccess * Refactor parameter assignments to fix linter warnings ## Description ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.sql.server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/sql/server/README.md | 21 +- avm/res/sql/server/database/README.md | 1 - avm/res/sql/server/database/main.bicep | 26 +- avm/res/sql/server/database/main.json | 30 +- avm/res/sql/server/elastic-pool/README.md | 1 - avm/res/sql/server/elastic-pool/main.bicep | 2 +- avm/res/sql/server/elastic-pool/main.json | 4 +- avm/res/sql/server/main.bicep | 155 ++++----- avm/res/sql/server/main.json | 318 ++++++++++++------ .../sql/server/tests/e2e/max/main.test.bicep | 21 +- .../tests/e2e/waf-aligned/main.test.bicep | 22 +- avm/res/sql/server/version.json | 2 +- 12 files changed, 359 insertions(+), 244 deletions(-) diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index 92be8ea923..1869610a60 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -471,7 +471,6 @@ module server 'br/public:avm/res/sql/server:' = { ] elasticPools: [ { - maintenanceConfigurationId: '' name: 'sqlsmax-ep-001' skuCapacity: 10 skuName: 'GP_Gen5' @@ -641,7 +640,6 @@ module server 'br/public:avm/res/sql/server:' = { "elasticPools": { "value": [ { - "maintenanceConfigurationId": "", "name": "sqlsmax-ep-001", "skuCapacity": 10, "skuName": "GP_Gen5", @@ -829,7 +827,6 @@ param databases = [ ] param elasticPools = [ { - maintenanceConfigurationId: '' name: 'sqlsmax-ep-001' skuCapacity: 10 skuName: 'GP_Gen5' @@ -1680,6 +1677,7 @@ param vulnerabilityAssessmentsObj = { | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`encryptionProtectorObj`](#parameter-encryptionprotectorobj) | object | The encryption protection configuration. | | [`firewallRules`](#parameter-firewallrules) | array | The firewall rules to create in the server. | +| [`isIPv6Enabled`](#parameter-isipv6enabled) | string | Whether or not to enable IPv6 support for this server. | | [`keys`](#parameter-keys) | array | The keys to configure. | | [`location`](#parameter-location) | string | Location for all resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | @@ -1878,6 +1876,21 @@ The firewall rules to create in the server. - Type: array - Default: `[]` +### Parameter: `isIPv6Enabled` + +Whether or not to enable IPv6 support for this server. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + ### Parameter: `keys` The keys to configure. @@ -1971,6 +1984,7 @@ Minimal TLS version allowed. '1.0' '1.1' '1.2' + '1.3' ] ``` @@ -2393,6 +2407,7 @@ Whether or not public network access is allowed for this resource. For security '' 'Disabled' 'Enabled' + 'SecuredByPerimeter' ] ``` diff --git a/avm/res/sql/server/database/README.md b/avm/res/sql/server/database/README.md index e2268849ef..1abb8e303b 100644 --- a/avm/res/sql/server/database/README.md +++ b/avm/res/sql/server/database/README.md @@ -324,7 +324,6 @@ Maintenance configuration ID assigned to the database. This configuration define - Required: No - Type: string -- Default: `''` ### Parameter: `maxSizeBytes` diff --git a/avm/res/sql/server/database/main.bicep b/avm/res/sql/server/database/main.bicep index f26259ab84..8919f4c720 100644 --- a/avm/res/sql/server/database/main.bicep +++ b/avm/res/sql/server/database/main.bicep @@ -112,7 +112,7 @@ param requestedBackupStorageRedundancy string = '' param isLedgerOn bool = false @description('Optional. Maintenance configuration ID assigned to the database. This configuration defines the period when the maintenance updates will occur.') -param maintenanceConfigurationId string = '' +param maintenanceConfigurationId string? @description('Optional. The short term backup retention policy to create for the database.') param backupShortTermRetentionPolicy object = {} @@ -164,7 +164,7 @@ resource database 'Microsoft.Sql/servers/databases@2023-08-01-preview' = { highAvailabilityReplicaCount: highAvailabilityReplicaCount requestedBackupStorageRedundancy: any(requestedBackupStorageRedundancy) isLedgerOn: isLedgerOn - maintenanceConfigurationId: !empty(maintenanceConfigurationId) ? maintenanceConfigurationId : null + maintenanceConfigurationId: maintenanceConfigurationId elasticPoolId: elasticPoolId createMode: createMode sourceDatabaseId: !empty(sourceDatabaseResourceId) ? sourceDatabaseResourceId : null @@ -211,12 +211,8 @@ module database_backupShortTermRetentionPolicy 'backup-short-term-retention-poli params: { serverName: serverName databaseName: database.name - diffBackupIntervalInHours: contains(backupShortTermRetentionPolicy, 'diffBackupIntervalInHours') - ? backupShortTermRetentionPolicy.diffBackupIntervalInHours - : 24 - retentionDays: contains(backupShortTermRetentionPolicy, 'retentionDays') - ? backupShortTermRetentionPolicy.retentionDays - : 7 + diffBackupIntervalInHours: backupShortTermRetentionPolicy.?diffBackupIntervalInHours ?? 24 + retentionDays: backupShortTermRetentionPolicy.?retentionDays ?? 7 } } @@ -225,16 +221,10 @@ module database_backupLongTermRetentionPolicy 'backup-long-term-retention-policy params: { serverName: serverName databaseName: database.name - weeklyRetention: contains(backupLongTermRetentionPolicy, 'weeklyRetention') - ? backupLongTermRetentionPolicy.weeklyRetention - : '' - monthlyRetention: contains(backupLongTermRetentionPolicy, 'monthlyRetention') - ? backupLongTermRetentionPolicy.monthlyRetention - : '' - yearlyRetention: contains(backupLongTermRetentionPolicy, 'yearlyRetention') - ? backupLongTermRetentionPolicy.yearlyRetention - : '' - weekOfYear: contains(backupLongTermRetentionPolicy, 'weekOfYear') ? backupLongTermRetentionPolicy.weekOfYear : 1 + weeklyRetention: backupLongTermRetentionPolicy.?weeklyRetention ?? '' + monthlyRetention: backupLongTermRetentionPolicy.?monthlyRetention ?? '' + yearlyRetention: backupLongTermRetentionPolicy.?yearlyRetention ?? '' + weekOfYear: backupLongTermRetentionPolicy.?weekOfYear ?? 1 } } diff --git a/avm/res/sql/server/database/main.json b/avm/res/sql/server/database/main.json index a28b55efe8..4be7b1af7f 100644 --- a/avm/res/sql/server/database/main.json +++ b/avm/res/sql/server/database/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "6019999815954957727" + "templateHash": "18021918128213514276" }, "name": "SQL Server Database", "description": "This module deploys an Azure SQL Server Database.", @@ -355,7 +355,7 @@ }, "maintenanceConfigurationId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Maintenance configuration ID assigned to the database. This configuration defines the period when the maintenance updates will occur." } @@ -404,7 +404,7 @@ "highAvailabilityReplicaCount": "[parameters('highAvailabilityReplicaCount')]", "requestedBackupStorageRedundancy": "[parameters('requestedBackupStorageRedundancy')]", "isLedgerOn": "[parameters('isLedgerOn')]", - "maintenanceConfigurationId": "[if(not(empty(parameters('maintenanceConfigurationId'))), parameters('maintenanceConfigurationId'), null())]", + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationId')]", "elasticPoolId": "[parameters('elasticPoolId')]", "createMode": "[parameters('createMode')]", "sourceDatabaseId": "[if(not(empty(parameters('sourceDatabaseResourceId'))), parameters('sourceDatabaseResourceId'), null())]", @@ -474,8 +474,12 @@ "databaseName": { "value": "[parameters('name')]" }, - "diffBackupIntervalInHours": "[if(contains(parameters('backupShortTermRetentionPolicy'), 'diffBackupIntervalInHours'), createObject('value', parameters('backupShortTermRetentionPolicy').diffBackupIntervalInHours), createObject('value', 24))]", - "retentionDays": "[if(contains(parameters('backupShortTermRetentionPolicy'), 'retentionDays'), createObject('value', parameters('backupShortTermRetentionPolicy').retentionDays), createObject('value', 7))]" + "diffBackupIntervalInHours": { + "value": "[coalesce(tryGet(parameters('backupShortTermRetentionPolicy'), 'diffBackupIntervalInHours'), 24)]" + }, + "retentionDays": { + "value": "[coalesce(tryGet(parameters('backupShortTermRetentionPolicy'), 'retentionDays'), 7)]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -574,10 +578,18 @@ "databaseName": { "value": "[parameters('name')]" }, - "weeklyRetention": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'weeklyRetention'), createObject('value', parameters('backupLongTermRetentionPolicy').weeklyRetention), createObject('value', ''))]", - "monthlyRetention": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'monthlyRetention'), createObject('value', parameters('backupLongTermRetentionPolicy').monthlyRetention), createObject('value', ''))]", - "yearlyRetention": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'yearlyRetention'), createObject('value', parameters('backupLongTermRetentionPolicy').yearlyRetention), createObject('value', ''))]", - "weekOfYear": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'weekOfYear'), createObject('value', parameters('backupLongTermRetentionPolicy').weekOfYear), createObject('value', 1))]" + "weeklyRetention": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'weeklyRetention'), '')]" + }, + "monthlyRetention": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'monthlyRetention'), '')]" + }, + "yearlyRetention": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'yearlyRetention'), '')]" + }, + "weekOfYear": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'weekOfYear'), 1)]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", diff --git a/avm/res/sql/server/elastic-pool/README.md b/avm/res/sql/server/elastic-pool/README.md index 69b5e3ec50..ef598e5fa3 100644 --- a/avm/res/sql/server/elastic-pool/README.md +++ b/avm/res/sql/server/elastic-pool/README.md @@ -112,7 +112,6 @@ Maintenance configuration resource ID assigned to the elastic pool. This configu - Required: No - Type: string -- Default: `''` ### Parameter: `maxSizeBytes` diff --git a/avm/res/sql/server/elastic-pool/main.bicep b/avm/res/sql/server/elastic-pool/main.bicep index 606aded8d8..df5d5510ea 100644 --- a/avm/res/sql/server/elastic-pool/main.bicep +++ b/avm/res/sql/server/elastic-pool/main.bicep @@ -34,7 +34,7 @@ param highAvailabilityReplicaCount int? param licenseType string = 'LicenseIncluded' @description('Optional. Maintenance configuration resource ID assigned to the elastic pool. This configuration defines the period when the maintenance updates will will occur.') -param maintenanceConfigurationId string = '' +param maintenanceConfigurationId string? @description('Optional. The storage limit for the database elastic pool in bytes.') param maxSizeBytes int = 34359738368 diff --git a/avm/res/sql/server/elastic-pool/main.json b/avm/res/sql/server/elastic-pool/main.json index 018727aa52..5acc2b0818 100644 --- a/avm/res/sql/server/elastic-pool/main.json +++ b/avm/res/sql/server/elastic-pool/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "18037703368269722870" + "templateHash": "17774091526328280898" }, "name": "SQL Server Elastic Pool", "description": "This module deploys an Azure SQL Server Elastic Pool.", @@ -80,7 +80,7 @@ }, "maintenanceConfigurationId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Maintenance configuration resource ID assigned to the elastic pool. This configuration defines the period when the maintenance updates will will occur." } diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep index 6a3921b4eb..3919e4655a 100644 --- a/avm/res/sql/server/main.bicep +++ b/avm/res/sql/server/main.bicep @@ -58,10 +58,18 @@ param administrators object = {} '1.0' '1.1' '1.2' + '1.3' ]) @description('Optional. Minimal TLS version allowed.') param minimalTlsVersion string = '1.2' +@allowed([ + 'Disabled' + 'Enabled' +]) +@description('Optional. Whether or not to enable IPv6 support for this server.') +param isIPv6Enabled string = 'Disabled' + @description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') param privateEndpoints privateEndpointType @@ -70,6 +78,7 @@ param privateEndpoints privateEndpointType '' 'Enabled' 'Disabled' + 'SecuredByPerimeter' ]) param publicNetworkAccess string = '' @@ -202,9 +211,10 @@ resource server 'Microsoft.Sql/servers@2023-08-01-preview' = { minimalTlsVersion: minimalTlsVersion primaryUserAssignedIdentityId: !empty(primaryUserAssignedIdentityId) ? primaryUserAssignedIdentityId : null publicNetworkAccess: !empty(publicNetworkAccess) - ? any(publicNetworkAccess) + ? publicNetworkAccess : (!empty(privateEndpoints) && empty(firewallRules) && empty(virtualNetworkRules) ? 'Disabled' : null) restrictOutboundNetworkAccess: !empty(restrictOutboundNetworkAccess) ? restrictOutboundNetworkAccess : null + isIPv6Enabled: isIPv6Enabled } } @@ -241,48 +251,34 @@ module server_databases 'database/main.bicep' = [ params: { name: database.name serverName: server.name - skuTier: contains(database, 'skuTier') ? database.skuTier : 'GeneralPurpose' - skuName: contains(database, 'skuName') ? database.skuName : 'GP_Gen5_2' + skuTier: database.?skuTier ?? 'GeneralPurpose' + skuName: database.?skuName ?? 'GP_Gen5_2' skuCapacity: database.?skuCapacity - skuFamily: contains(database, 'skuFamily') ? database.skuFamily : '' - skuSize: contains(database, 'skuSize') ? database.skuSize : '' - collation: contains(database, 'collation') ? database.collation : 'SQL_Latin1_General_CP1_CI_AS' - maxSizeBytes: contains(database, 'maxSizeBytes') ? database.maxSizeBytes : 34359738368 - autoPauseDelay: contains(database, 'autoPauseDelay') ? database.autoPauseDelay : 0 + skuFamily: database.?skuFamily ?? '' + skuSize: database.?skuSize ?? '' + collation: database.?collation ?? 'SQL_Latin1_General_CP1_CI_AS' + maxSizeBytes: database.?maxSizeBytes ?? 34359738368 + autoPauseDelay: database.?autoPauseDelay ?? 0 diagnosticSettings: database.?diagnosticSettings - isLedgerOn: contains(database, 'isLedgerOn') ? database.isLedgerOn : false + isLedgerOn: database.?isLedgerOn ?? false location: location - licenseType: contains(database, 'licenseType') ? database.licenseType : '' - maintenanceConfigurationId: contains(database, 'maintenanceConfigurationId') - ? database.maintenanceConfigurationId - : '' - minCapacity: contains(database, 'minCapacity') ? database.minCapacity : '' - highAvailabilityReplicaCount: contains(database, 'highAvailabilityReplicaCount') - ? database.highAvailabilityReplicaCount - : 0 - readScale: contains(database, 'readScale') ? database.readScale : 'Disabled' - requestedBackupStorageRedundancy: contains(database, 'requestedBackupStorageRedundancy') - ? database.requestedBackupStorageRedundancy - : '' - sampleName: contains(database, 'sampleName') ? database.sampleName : '' + licenseType: database.?licenseType ?? '' + maintenanceConfigurationId: database.?maintenanceConfigurationId + minCapacity: database.?minCapacity ?? '' + highAvailabilityReplicaCount: database.?highAvailabilityReplicaCount ?? 0 + readScale: database.?readScale ?? 'Disabled' + requestedBackupStorageRedundancy: database.?requestedBackupStorageRedundancy ?? '' + sampleName: database.?sampleName ?? '' tags: database.?tags ?? tags - zoneRedundant: contains(database, 'zoneRedundant') ? database.zoneRedundant : true - elasticPoolId: contains(database, 'elasticPoolId') ? database.elasticPoolId : '' - backupShortTermRetentionPolicy: contains(database, 'backupShortTermRetentionPolicy') - ? database.backupShortTermRetentionPolicy - : {} - backupLongTermRetentionPolicy: contains(database, 'backupLongTermRetentionPolicy') - ? database.backupLongTermRetentionPolicy - : {} - createMode: contains(database, 'createMode') ? database.createMode : 'Default' - sourceDatabaseResourceId: contains(database, 'sourceDatabaseResourceId') ? database.sourceDatabaseResourceId : '' - sourceDatabaseDeletionDate: contains(database, 'sourceDatabaseDeletionDate') - ? database.sourceDatabaseDeletionDate - : '' - recoveryServicesRecoveryPointResourceId: contains(database, 'recoveryServicesRecoveryPointResourceId') - ? database.recoveryServicesRecoveryPointResourceId - : '' - restorePointInTime: contains(database, 'restorePointInTime') ? database.restorePointInTime : '' + zoneRedundant: database.?zoneRedundant ?? true + elasticPoolId: database.?elasticPoolId ?? '' + backupShortTermRetentionPolicy: database.?backupShortTermRetentionPolicy ?? {} + backupLongTermRetentionPolicy: database.?backupLongTermRetentionPolicy ?? {} + createMode: database.?createMode ?? 'Default' + sourceDatabaseResourceId: database.?sourceDatabaseResourceId ?? '' + sourceDatabaseDeletionDate: database.?sourceDatabaseDeletionDate ?? '' + recoveryServicesRecoveryPointResourceId: database.?recoveryServicesRecoveryPointResourceId ?? '' + restorePointInTime: database.?restorePointInTime ?? '' } dependsOn: [ server_elasticPools // Enables us to add databases to existing elastic pools @@ -296,19 +292,17 @@ module server_elasticPools 'elastic-pool/main.bicep' = [ params: { name: elasticPool.name serverName: server.name - databaseMaxCapacity: contains(elasticPool, 'databaseMaxCapacity') ? elasticPool.databaseMaxCapacity : 2 - databaseMinCapacity: contains(elasticPool, 'databaseMinCapacity') ? elasticPool.databaseMinCapacity : 0 + databaseMaxCapacity: elasticPool.?databaseMaxCapacity ?? 2 + databaseMinCapacity: elasticPool.?databaseMinCapacity ?? 0 highAvailabilityReplicaCount: elasticPool.?highAvailabilityReplicaCount - licenseType: contains(elasticPool, 'licenseType') ? elasticPool.licenseType : 'LicenseIncluded' - maintenanceConfigurationId: contains(elasticPool, 'maintenanceConfigurationId') - ? elasticPool.maintenanceConfigurationId - : '' - maxSizeBytes: contains(elasticPool, 'maxSizeBytes') ? elasticPool.maxSizeBytes : 34359738368 + licenseType: elasticPool.?licenseType ?? 'LicenseIncluded' + maintenanceConfigurationId: elasticPool.?maintenanceConfigurationId + maxSizeBytes: elasticPool.?maxSizeBytes ?? 34359738368 minCapacity: elasticPool.?minCapacity - skuCapacity: contains(elasticPool, 'skuCapacity') ? elasticPool.skuCapacity : 2 - skuName: contains(elasticPool, 'skuName') ? elasticPool.skuName : 'GP_Gen5' - skuTier: contains(elasticPool, 'skuTier') ? elasticPool.skuTier : 'GeneralPurpose' - zoneRedundant: contains(elasticPool, 'zoneRedundant') ? elasticPool.zoneRedundant : true + skuCapacity: elasticPool.?skuCapacity ?? 2 + skuName: elasticPool.?skuName ?? 'GP_Gen5' + skuTier: elasticPool.?skuTier ?? 'GeneralPurpose' + zoneRedundant: elasticPool.?zoneRedundant ?? true location: location tags: elasticPool.?tags ?? tags } @@ -373,8 +367,8 @@ module server_firewallRules 'firewall-rule/main.bicep' = [ params: { name: firewallRule.name serverName: server.name - endIpAddress: contains(firewallRule, 'endIpAddress') ? firewallRule.endIpAddress : '0.0.0.0' - startIpAddress: contains(firewallRule, 'startIpAddress') ? firewallRule.startIpAddress : '0.0.0.0' + endIpAddress: firewallRule.?endIpAddress ?? '0.0.0.0' + startIpAddress: firewallRule.?startIpAddress ?? '0.0.0.0' } } ] @@ -385,9 +379,7 @@ module server_virtualNetworkRules 'virtual-network-rule/main.bicep' = [ params: { name: virtualNetworkRule.name serverName: server.name - ignoreMissingVnetServiceEndpoint: contains(virtualNetworkRule, 'ignoreMissingVnetServiceEndpoint') - ? virtualNetworkRule.ignoreMissingVnetServiceEndpoint - : false + ignoreMissingVnetServiceEndpoint: virtualNetworkRule.?ignoreMissingVnetServiceEndpoint ?? false virtualNetworkSubnetId: virtualNetworkRule.virtualNetworkSubnetId } } @@ -399,17 +391,13 @@ module server_securityAlertPolicies 'security-alert-policy/main.bicep' = [ params: { name: securityAlertPolicy.name serverName: server.name - disabledAlerts: contains(securityAlertPolicy, 'disabledAlerts') ? securityAlertPolicy.disabledAlerts : [] - emailAccountAdmins: contains(securityAlertPolicy, 'emailAccountAdmins') - ? securityAlertPolicy.emailAccountAdmins - : false - emailAddresses: contains(securityAlertPolicy, 'emailAddresses') ? securityAlertPolicy.emailAddresses : [] - retentionDays: contains(securityAlertPolicy, 'retentionDays') ? securityAlertPolicy.retentionDays : 0 - state: contains(securityAlertPolicy, 'state') ? securityAlertPolicy.state : 'Disabled' - storageAccountAccessKey: contains(securityAlertPolicy, 'storageAccountAccessKey') - ? securityAlertPolicy.storageAccountAccessKey - : '' - storageEndpoint: contains(securityAlertPolicy, 'storageEndpoint') ? securityAlertPolicy.storageEndpoint : '' + disabledAlerts: securityAlertPolicy.?disabledAlerts ?? [] + emailAccountAdmins: securityAlertPolicy.?emailAccountAdmins ?? false + emailAddresses: securityAlertPolicy.?emailAddresses ?? [] + retentionDays: securityAlertPolicy.?retentionDays ?? 0 + state: securityAlertPolicy.?state ?? 'Disabled' + storageAccountAccessKey: securityAlertPolicy.?storageAccountAccessKey ?? '' + storageEndpoint: securityAlertPolicy.?storageEndpoint ?? '' } } ] @@ -419,25 +407,12 @@ module server_vulnerabilityAssessment 'vulnerability-assessment/main.bicep' = if params: { serverName: server.name name: vulnerabilityAssessmentsObj.name - recurringScansEmails: contains(vulnerabilityAssessmentsObj, 'recurringScansEmails') - ? vulnerabilityAssessmentsObj.recurringScansEmails - : [] - recurringScansEmailSubscriptionAdmins: contains( - vulnerabilityAssessmentsObj, - 'recurringScansEmailSubscriptionAdmins' - ) - ? vulnerabilityAssessmentsObj.recurringScansEmailSubscriptionAdmins - : false - recurringScansIsEnabled: contains(vulnerabilityAssessmentsObj, 'recurringScansIsEnabled') - ? vulnerabilityAssessmentsObj.recurringScansIsEnabled - : false + recurringScansEmails: vulnerabilityAssessmentsObj.?recurringScansEmails ?? [] + recurringScansEmailSubscriptionAdmins: vulnerabilityAssessmentsObj.?recurringScansEmailSubscriptionAdmins ?? false + recurringScansIsEnabled: vulnerabilityAssessmentsObj.?recurringScansIsEnabled ?? false storageAccountResourceId: vulnerabilityAssessmentsObj.storageAccountResourceId - useStorageAccountAccessKey: contains(vulnerabilityAssessmentsObj, 'useStorageAccountAccessKey') - ? vulnerabilityAssessmentsObj.useStorageAccountAccessKey - : false - createStorageRoleAssignment: contains(vulnerabilityAssessmentsObj, 'createStorageRoleAssignment') - ? vulnerabilityAssessmentsObj.createStorageRoleAssignment - : true + useStorageAccountAccessKey: vulnerabilityAssessmentsObj.?useStorageAccountAccessKey ?? false + createStorageRoleAssignment: vulnerabilityAssessmentsObj.?createStorageRoleAssignment ?? true } dependsOn: [ server_securityAlertPolicies @@ -450,8 +425,8 @@ module server_keys 'key/main.bicep' = [ params: { name: key.?name serverName: server.name - serverKeyType: contains(key, 'serverKeyType') ? key.serverKeyType : 'ServiceManaged' - uri: contains(key, 'uri') ? key.uri : '' + serverKeyType: key.?serverKeyType ?? 'ServiceManaged' + uri: key.?uri ?? '' } } ] @@ -461,12 +436,8 @@ module server_encryptionProtector 'encryption-protector/main.bicep' = if (!empty params: { sqlServerName: server.name serverKeyName: encryptionProtectorObj.serverKeyName - serverKeyType: contains(encryptionProtectorObj, 'serverKeyType') - ? encryptionProtectorObj.serverKeyType - : 'ServiceManaged' - autoRotationEnabled: contains(encryptionProtectorObj, 'autoRotationEnabled') - ? encryptionProtectorObj.autoRotationEnabled - : true + serverKeyType: encryptionProtectorObj.?serverKeyType ?? 'ServiceManaged' + autoRotationEnabled: encryptionProtectorObj.?autoRotationEnabled ?? true } dependsOn: [ server_keys diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json index af15b03a96..66bd386f4d 100644 --- a/avm/res/sql/server/main.json +++ b/avm/res/sql/server/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "779644860652942835" + "version": "0.29.47.4906", + "templateHash": "12721468399061919493" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", @@ -616,12 +616,24 @@ "allowedValues": [ "1.0", "1.1", - "1.2" + "1.2", + "1.3" ], "metadata": { "description": "Optional. Minimal TLS version allowed." } }, + "isIPv6Enabled": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not to enable IPv6 support for this server." + } + }, "privateEndpoints": { "$ref": "#/definitions/privateEndpointType", "metadata": { @@ -634,7 +646,8 @@ "allowedValues": [ "", "Enabled", - "Disabled" + "Disabled", + "SecuredByPerimeter" ], "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 neither firewall rules nor virtual network rules are set." @@ -742,7 +755,8 @@ "minimalTlsVersion": "[parameters('minimalTlsVersion')]", "primaryUserAssignedIdentityId": "[if(not(empty(parameters('primaryUserAssignedIdentityId'))), parameters('primaryUserAssignedIdentityId'), null())]", "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(and(not(empty(parameters('privateEndpoints'))), empty(parameters('firewallRules'))), empty(parameters('virtualNetworkRules'))), 'Disabled', null()))]", - "restrictOutboundNetworkAccess": "[if(not(empty(parameters('restrictOutboundNetworkAccess'))), parameters('restrictOutboundNetworkAccess'), null())]" + "restrictOutboundNetworkAccess": "[if(not(empty(parameters('restrictOutboundNetworkAccess'))), parameters('restrictOutboundNetworkAccess'), null())]", + "isIPv6Enabled": "[parameters('isIPv6Enabled')]" } }, "server_lock": { @@ -801,42 +815,90 @@ "serverName": { "value": "[parameters('name')]" }, - "skuTier": "[if(contains(parameters('databases')[copyIndex()], 'skuTier'), createObject('value', parameters('databases')[copyIndex()].skuTier), createObject('value', 'GeneralPurpose'))]", - "skuName": "[if(contains(parameters('databases')[copyIndex()], 'skuName'), createObject('value', parameters('databases')[copyIndex()].skuName), createObject('value', 'GP_Gen5_2'))]", + "skuTier": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'skuTier'), 'GeneralPurpose')]" + }, + "skuName": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'skuName'), 'GP_Gen5_2')]" + }, "skuCapacity": { "value": "[tryGet(parameters('databases')[copyIndex()], 'skuCapacity')]" }, - "skuFamily": "[if(contains(parameters('databases')[copyIndex()], 'skuFamily'), createObject('value', parameters('databases')[copyIndex()].skuFamily), createObject('value', ''))]", - "skuSize": "[if(contains(parameters('databases')[copyIndex()], 'skuSize'), createObject('value', parameters('databases')[copyIndex()].skuSize), createObject('value', ''))]", - "collation": "[if(contains(parameters('databases')[copyIndex()], 'collation'), createObject('value', parameters('databases')[copyIndex()].collation), createObject('value', 'SQL_Latin1_General_CP1_CI_AS'))]", - "maxSizeBytes": "[if(contains(parameters('databases')[copyIndex()], 'maxSizeBytes'), createObject('value', parameters('databases')[copyIndex()].maxSizeBytes), createObject('value', json('34359738368')))]", - "autoPauseDelay": "[if(contains(parameters('databases')[copyIndex()], 'autoPauseDelay'), createObject('value', parameters('databases')[copyIndex()].autoPauseDelay), createObject('value', 0))]", + "skuFamily": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'skuFamily'), '')]" + }, + "skuSize": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'skuSize'), '')]" + }, + "collation": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'collation'), 'SQL_Latin1_General_CP1_CI_AS')]" + }, + "maxSizeBytes": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'maxSizeBytes'), json('34359738368'))]" + }, + "autoPauseDelay": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'autoPauseDelay'), 0)]" + }, "diagnosticSettings": { "value": "[tryGet(parameters('databases')[copyIndex()], 'diagnosticSettings')]" }, - "isLedgerOn": "[if(contains(parameters('databases')[copyIndex()], 'isLedgerOn'), createObject('value', parameters('databases')[copyIndex()].isLedgerOn), createObject('value', false()))]", + "isLedgerOn": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'isLedgerOn'), false())]" + }, "location": { "value": "[parameters('location')]" }, - "licenseType": "[if(contains(parameters('databases')[copyIndex()], 'licenseType'), createObject('value', parameters('databases')[copyIndex()].licenseType), createObject('value', ''))]", - "maintenanceConfigurationId": "[if(contains(parameters('databases')[copyIndex()], 'maintenanceConfigurationId'), createObject('value', parameters('databases')[copyIndex()].maintenanceConfigurationId), createObject('value', ''))]", - "minCapacity": "[if(contains(parameters('databases')[copyIndex()], 'minCapacity'), createObject('value', parameters('databases')[copyIndex()].minCapacity), createObject('value', ''))]", - "highAvailabilityReplicaCount": "[if(contains(parameters('databases')[copyIndex()], 'highAvailabilityReplicaCount'), createObject('value', parameters('databases')[copyIndex()].highAvailabilityReplicaCount), createObject('value', 0))]", - "readScale": "[if(contains(parameters('databases')[copyIndex()], 'readScale'), createObject('value', parameters('databases')[copyIndex()].readScale), createObject('value', 'Disabled'))]", - "requestedBackupStorageRedundancy": "[if(contains(parameters('databases')[copyIndex()], 'requestedBackupStorageRedundancy'), createObject('value', parameters('databases')[copyIndex()].requestedBackupStorageRedundancy), createObject('value', ''))]", - "sampleName": "[if(contains(parameters('databases')[copyIndex()], 'sampleName'), createObject('value', parameters('databases')[copyIndex()].sampleName), createObject('value', ''))]", + "licenseType": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'licenseType'), '')]" + }, + "maintenanceConfigurationId": { + "value": "[tryGet(parameters('databases')[copyIndex()], 'maintenanceConfigurationId')]" + }, + "minCapacity": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'minCapacity'), '')]" + }, + "highAvailabilityReplicaCount": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'highAvailabilityReplicaCount'), 0)]" + }, + "readScale": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'readScale'), 'Disabled')]" + }, + "requestedBackupStorageRedundancy": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'requestedBackupStorageRedundancy'), '')]" + }, + "sampleName": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'sampleName'), '')]" + }, "tags": { "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'tags'), parameters('tags'))]" }, - "zoneRedundant": "[if(contains(parameters('databases')[copyIndex()], 'zoneRedundant'), createObject('value', parameters('databases')[copyIndex()].zoneRedundant), createObject('value', true()))]", - "elasticPoolId": "[if(contains(parameters('databases')[copyIndex()], 'elasticPoolId'), createObject('value', parameters('databases')[copyIndex()].elasticPoolId), createObject('value', ''))]", - "backupShortTermRetentionPolicy": "[if(contains(parameters('databases')[copyIndex()], 'backupShortTermRetentionPolicy'), createObject('value', parameters('databases')[copyIndex()].backupShortTermRetentionPolicy), createObject('value', createObject()))]", - "backupLongTermRetentionPolicy": "[if(contains(parameters('databases')[copyIndex()], 'backupLongTermRetentionPolicy'), createObject('value', parameters('databases')[copyIndex()].backupLongTermRetentionPolicy), createObject('value', createObject()))]", - "createMode": "[if(contains(parameters('databases')[copyIndex()], 'createMode'), createObject('value', parameters('databases')[copyIndex()].createMode), createObject('value', 'Default'))]", - "sourceDatabaseResourceId": "[if(contains(parameters('databases')[copyIndex()], 'sourceDatabaseResourceId'), createObject('value', parameters('databases')[copyIndex()].sourceDatabaseResourceId), createObject('value', ''))]", - "sourceDatabaseDeletionDate": "[if(contains(parameters('databases')[copyIndex()], 'sourceDatabaseDeletionDate'), createObject('value', parameters('databases')[copyIndex()].sourceDatabaseDeletionDate), createObject('value', ''))]", - "recoveryServicesRecoveryPointResourceId": "[if(contains(parameters('databases')[copyIndex()], 'recoveryServicesRecoveryPointResourceId'), createObject('value', parameters('databases')[copyIndex()].recoveryServicesRecoveryPointResourceId), createObject('value', ''))]", - "restorePointInTime": "[if(contains(parameters('databases')[copyIndex()], 'restorePointInTime'), createObject('value', parameters('databases')[copyIndex()].restorePointInTime), createObject('value', ''))]" + "zoneRedundant": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'zoneRedundant'), true())]" + }, + "elasticPoolId": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'elasticPoolId'), '')]" + }, + "backupShortTermRetentionPolicy": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'backupShortTermRetentionPolicy'), createObject())]" + }, + "backupLongTermRetentionPolicy": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'backupLongTermRetentionPolicy'), createObject())]" + }, + "createMode": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'createMode'), 'Default')]" + }, + "sourceDatabaseResourceId": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'sourceDatabaseResourceId'), '')]" + }, + "sourceDatabaseDeletionDate": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'sourceDatabaseDeletionDate'), '')]" + }, + "recoveryServicesRecoveryPointResourceId": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'recoveryServicesRecoveryPointResourceId'), '')]" + }, + "restorePointInTime": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'restorePointInTime'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -845,8 +907,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "11407307502843440892" + "version": "0.29.47.4906", + "templateHash": "18021918128213514276" }, "name": "SQL Server Database", "description": "This module deploys an Azure SQL Server Database.", @@ -1195,7 +1257,7 @@ }, "maintenanceConfigurationId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Maintenance configuration ID assigned to the database. This configuration defines the period when the maintenance updates will occur." } @@ -1244,7 +1306,7 @@ "highAvailabilityReplicaCount": "[parameters('highAvailabilityReplicaCount')]", "requestedBackupStorageRedundancy": "[parameters('requestedBackupStorageRedundancy')]", "isLedgerOn": "[parameters('isLedgerOn')]", - "maintenanceConfigurationId": "[if(not(empty(parameters('maintenanceConfigurationId'))), parameters('maintenanceConfigurationId'), null())]", + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationId')]", "elasticPoolId": "[parameters('elasticPoolId')]", "createMode": "[parameters('createMode')]", "sourceDatabaseId": "[if(not(empty(parameters('sourceDatabaseResourceId'))), parameters('sourceDatabaseResourceId'), null())]", @@ -1314,8 +1376,12 @@ "databaseName": { "value": "[parameters('name')]" }, - "diffBackupIntervalInHours": "[if(contains(parameters('backupShortTermRetentionPolicy'), 'diffBackupIntervalInHours'), createObject('value', parameters('backupShortTermRetentionPolicy').diffBackupIntervalInHours), createObject('value', 24))]", - "retentionDays": "[if(contains(parameters('backupShortTermRetentionPolicy'), 'retentionDays'), createObject('value', parameters('backupShortTermRetentionPolicy').retentionDays), createObject('value', 7))]" + "diffBackupIntervalInHours": { + "value": "[coalesce(tryGet(parameters('backupShortTermRetentionPolicy'), 'diffBackupIntervalInHours'), 24)]" + }, + "retentionDays": { + "value": "[coalesce(tryGet(parameters('backupShortTermRetentionPolicy'), 'retentionDays'), 7)]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1323,8 +1389,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "10836519140305169908" + "version": "0.29.47.4906", + "templateHash": "8635162595153731245" }, "name": "Azure SQL Server Database Short Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Short-Term Backup Retention Policy.", @@ -1414,10 +1480,18 @@ "databaseName": { "value": "[parameters('name')]" }, - "weeklyRetention": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'weeklyRetention'), createObject('value', parameters('backupLongTermRetentionPolicy').weeklyRetention), createObject('value', ''))]", - "monthlyRetention": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'monthlyRetention'), createObject('value', parameters('backupLongTermRetentionPolicy').monthlyRetention), createObject('value', ''))]", - "yearlyRetention": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'yearlyRetention'), createObject('value', parameters('backupLongTermRetentionPolicy').yearlyRetention), createObject('value', ''))]", - "weekOfYear": "[if(contains(parameters('backupLongTermRetentionPolicy'), 'weekOfYear'), createObject('value', parameters('backupLongTermRetentionPolicy').weekOfYear), createObject('value', 1))]" + "weeklyRetention": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'weeklyRetention'), '')]" + }, + "monthlyRetention": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'monthlyRetention'), '')]" + }, + "yearlyRetention": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'yearlyRetention'), '')]" + }, + "weekOfYear": { + "value": "[coalesce(tryGet(parameters('backupLongTermRetentionPolicy'), 'weekOfYear'), 1)]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1425,8 +1499,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "10064519186693398262" + "version": "0.29.47.4906", + "templateHash": "2778016138108001251" }, "name": "SQL Server Database Long Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Long-Term Backup Retention Policy.", @@ -1574,21 +1648,39 @@ "serverName": { "value": "[parameters('name')]" }, - "databaseMaxCapacity": "[if(contains(parameters('elasticPools')[copyIndex()], 'databaseMaxCapacity'), createObject('value', parameters('elasticPools')[copyIndex()].databaseMaxCapacity), createObject('value', 2))]", - "databaseMinCapacity": "[if(contains(parameters('elasticPools')[copyIndex()], 'databaseMinCapacity'), createObject('value', parameters('elasticPools')[copyIndex()].databaseMinCapacity), createObject('value', 0))]", + "databaseMaxCapacity": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'databaseMaxCapacity'), 2)]" + }, + "databaseMinCapacity": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'databaseMinCapacity'), 0)]" + }, "highAvailabilityReplicaCount": { "value": "[tryGet(parameters('elasticPools')[copyIndex()], 'highAvailabilityReplicaCount')]" }, - "licenseType": "[if(contains(parameters('elasticPools')[copyIndex()], 'licenseType'), createObject('value', parameters('elasticPools')[copyIndex()].licenseType), createObject('value', 'LicenseIncluded'))]", - "maintenanceConfigurationId": "[if(contains(parameters('elasticPools')[copyIndex()], 'maintenanceConfigurationId'), createObject('value', parameters('elasticPools')[copyIndex()].maintenanceConfigurationId), createObject('value', ''))]", - "maxSizeBytes": "[if(contains(parameters('elasticPools')[copyIndex()], 'maxSizeBytes'), createObject('value', parameters('elasticPools')[copyIndex()].maxSizeBytes), createObject('value', json('34359738368')))]", + "licenseType": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'licenseType'), 'LicenseIncluded')]" + }, + "maintenanceConfigurationId": { + "value": "[tryGet(parameters('elasticPools')[copyIndex()], 'maintenanceConfigurationId')]" + }, + "maxSizeBytes": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'maxSizeBytes'), json('34359738368'))]" + }, "minCapacity": { "value": "[tryGet(parameters('elasticPools')[copyIndex()], 'minCapacity')]" }, - "skuCapacity": "[if(contains(parameters('elasticPools')[copyIndex()], 'skuCapacity'), createObject('value', parameters('elasticPools')[copyIndex()].skuCapacity), createObject('value', 2))]", - "skuName": "[if(contains(parameters('elasticPools')[copyIndex()], 'skuName'), createObject('value', parameters('elasticPools')[copyIndex()].skuName), createObject('value', 'GP_Gen5'))]", - "skuTier": "[if(contains(parameters('elasticPools')[copyIndex()], 'skuTier'), createObject('value', parameters('elasticPools')[copyIndex()].skuTier), createObject('value', 'GeneralPurpose'))]", - "zoneRedundant": "[if(contains(parameters('elasticPools')[copyIndex()], 'zoneRedundant'), createObject('value', parameters('elasticPools')[copyIndex()].zoneRedundant), createObject('value', true()))]", + "skuCapacity": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'skuCapacity'), 2)]" + }, + "skuName": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'skuName'), 'GP_Gen5')]" + }, + "skuTier": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'skuTier'), 'GeneralPurpose')]" + }, + "zoneRedundant": { + "value": "[coalesce(tryGet(parameters('elasticPools')[copyIndex()], 'zoneRedundant'), true())]" + }, "location": { "value": "[parameters('location')]" }, @@ -1603,8 +1695,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "1486548652639885128" + "version": "0.29.47.4906", + "templateHash": "17774091526328280898" }, "name": "SQL Server Elastic Pool", "description": "This module deploys an Azure SQL Server Elastic Pool.", @@ -1678,7 +1770,7 @@ }, "maintenanceConfigurationId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Maintenance configuration resource ID assigned to the elastic pool. This configuration defines the period when the maintenance updates will will occur." } @@ -2576,8 +2668,12 @@ "serverName": { "value": "[parameters('name')]" }, - "endIpAddress": "[if(contains(parameters('firewallRules')[copyIndex()], 'endIpAddress'), createObject('value', parameters('firewallRules')[copyIndex()].endIpAddress), createObject('value', '0.0.0.0'))]", - "startIpAddress": "[if(contains(parameters('firewallRules')[copyIndex()], 'startIpAddress'), createObject('value', parameters('firewallRules')[copyIndex()].startIpAddress), createObject('value', '0.0.0.0'))]" + "endIpAddress": { + "value": "[coalesce(tryGet(parameters('firewallRules')[copyIndex()], 'endIpAddress'), '0.0.0.0')]" + }, + "startIpAddress": { + "value": "[coalesce(tryGet(parameters('firewallRules')[copyIndex()], 'startIpAddress'), '0.0.0.0')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2585,8 +2681,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "6449556555046717103" + "version": "0.29.47.4906", + "templateHash": "7779473510493338097" }, "name": "Azure SQL Server Firewall Rule", "description": "This module deploys an Azure SQL Server Firewall Rule.", @@ -2680,7 +2776,9 @@ "serverName": { "value": "[parameters('name')]" }, - "ignoreMissingVnetServiceEndpoint": "[if(contains(parameters('virtualNetworkRules')[copyIndex()], 'ignoreMissingVnetServiceEndpoint'), createObject('value', parameters('virtualNetworkRules')[copyIndex()].ignoreMissingVnetServiceEndpoint), createObject('value', false()))]", + "ignoreMissingVnetServiceEndpoint": { + "value": "[coalesce(tryGet(parameters('virtualNetworkRules')[copyIndex()], 'ignoreMissingVnetServiceEndpoint'), false())]" + }, "virtualNetworkSubnetId": { "value": "[parameters('virtualNetworkRules')[copyIndex()].virtualNetworkSubnetId]" } @@ -2691,8 +2789,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "4969955763304077350" + "version": "0.29.47.4906", + "templateHash": "7859066741604114060" }, "name": "Azure SQL Server Virtual Network Rules", "description": "This module deploys an Azure SQL Server Virtual Network Rule.", @@ -2785,13 +2883,27 @@ "serverName": { "value": "[parameters('name')]" }, - "disabledAlerts": "[if(contains(parameters('securityAlertPolicies')[copyIndex()], 'disabledAlerts'), createObject('value', parameters('securityAlertPolicies')[copyIndex()].disabledAlerts), createObject('value', createArray()))]", - "emailAccountAdmins": "[if(contains(parameters('securityAlertPolicies')[copyIndex()], 'emailAccountAdmins'), createObject('value', parameters('securityAlertPolicies')[copyIndex()].emailAccountAdmins), createObject('value', false()))]", - "emailAddresses": "[if(contains(parameters('securityAlertPolicies')[copyIndex()], 'emailAddresses'), createObject('value', parameters('securityAlertPolicies')[copyIndex()].emailAddresses), createObject('value', createArray()))]", - "retentionDays": "[if(contains(parameters('securityAlertPolicies')[copyIndex()], 'retentionDays'), createObject('value', parameters('securityAlertPolicies')[copyIndex()].retentionDays), createObject('value', 0))]", - "state": "[if(contains(parameters('securityAlertPolicies')[copyIndex()], 'state'), createObject('value', parameters('securityAlertPolicies')[copyIndex()].state), createObject('value', 'Disabled'))]", - "storageAccountAccessKey": "[if(contains(parameters('securityAlertPolicies')[copyIndex()], 'storageAccountAccessKey'), createObject('value', parameters('securityAlertPolicies')[copyIndex()].storageAccountAccessKey), createObject('value', ''))]", - "storageEndpoint": "[if(contains(parameters('securityAlertPolicies')[copyIndex()], 'storageEndpoint'), createObject('value', parameters('securityAlertPolicies')[copyIndex()].storageEndpoint), createObject('value', ''))]" + "disabledAlerts": { + "value": "[coalesce(tryGet(parameters('securityAlertPolicies')[copyIndex()], 'disabledAlerts'), createArray())]" + }, + "emailAccountAdmins": { + "value": "[coalesce(tryGet(parameters('securityAlertPolicies')[copyIndex()], 'emailAccountAdmins'), false())]" + }, + "emailAddresses": { + "value": "[coalesce(tryGet(parameters('securityAlertPolicies')[copyIndex()], 'emailAddresses'), createArray())]" + }, + "retentionDays": { + "value": "[coalesce(tryGet(parameters('securityAlertPolicies')[copyIndex()], 'retentionDays'), 0)]" + }, + "state": { + "value": "[coalesce(tryGet(parameters('securityAlertPolicies')[copyIndex()], 'state'), 'Disabled')]" + }, + "storageAccountAccessKey": { + "value": "[coalesce(tryGet(parameters('securityAlertPolicies')[copyIndex()], 'storageAccountAccessKey'), '')]" + }, + "storageEndpoint": { + "value": "[coalesce(tryGet(parameters('securityAlertPolicies')[copyIndex()], 'storageEndpoint'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2799,8 +2911,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "15406914222375641032" + "version": "0.29.47.4906", + "templateHash": "6025191760768766090" }, "name": "Azure SQL Server Security Alert Policies", "description": "This module deploys an Azure SQL Server Security Alert Policy.", @@ -2935,14 +3047,24 @@ "name": { "value": "[parameters('vulnerabilityAssessmentsObj').name]" }, - "recurringScansEmails": "[if(contains(parameters('vulnerabilityAssessmentsObj'), 'recurringScansEmails'), createObject('value', parameters('vulnerabilityAssessmentsObj').recurringScansEmails), createObject('value', createArray()))]", - "recurringScansEmailSubscriptionAdmins": "[if(contains(parameters('vulnerabilityAssessmentsObj'), 'recurringScansEmailSubscriptionAdmins'), createObject('value', parameters('vulnerabilityAssessmentsObj').recurringScansEmailSubscriptionAdmins), createObject('value', false()))]", - "recurringScansIsEnabled": "[if(contains(parameters('vulnerabilityAssessmentsObj'), 'recurringScansIsEnabled'), createObject('value', parameters('vulnerabilityAssessmentsObj').recurringScansIsEnabled), createObject('value', false()))]", + "recurringScansEmails": { + "value": "[coalesce(tryGet(parameters('vulnerabilityAssessmentsObj'), 'recurringScansEmails'), createArray())]" + }, + "recurringScansEmailSubscriptionAdmins": { + "value": "[coalesce(tryGet(parameters('vulnerabilityAssessmentsObj'), 'recurringScansEmailSubscriptionAdmins'), false())]" + }, + "recurringScansIsEnabled": { + "value": "[coalesce(tryGet(parameters('vulnerabilityAssessmentsObj'), 'recurringScansIsEnabled'), false())]" + }, "storageAccountResourceId": { "value": "[parameters('vulnerabilityAssessmentsObj').storageAccountResourceId]" }, - "useStorageAccountAccessKey": "[if(contains(parameters('vulnerabilityAssessmentsObj'), 'useStorageAccountAccessKey'), createObject('value', parameters('vulnerabilityAssessmentsObj').useStorageAccountAccessKey), createObject('value', false()))]", - "createStorageRoleAssignment": "[if(contains(parameters('vulnerabilityAssessmentsObj'), 'createStorageRoleAssignment'), createObject('value', parameters('vulnerabilityAssessmentsObj').createStorageRoleAssignment), createObject('value', true()))]" + "useStorageAccountAccessKey": { + "value": "[coalesce(tryGet(parameters('vulnerabilityAssessmentsObj'), 'useStorageAccountAccessKey'), false())]" + }, + "createStorageRoleAssignment": { + "value": "[coalesce(tryGet(parameters('vulnerabilityAssessmentsObj'), 'createStorageRoleAssignment'), true())]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2950,8 +3072,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "11004049200994426011" + "version": "0.29.47.4906", + "templateHash": "5682596516926040129" }, "name": "Azure SQL Server Vulnerability Assessments", "description": "This module deploys an Azure SQL Server Vulnerability Assessment.", @@ -3053,8 +3175,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "13956215614091387428" + "version": "0.29.47.4906", + "templateHash": "17251889896692066430" } }, "parameters": { @@ -3132,8 +3254,12 @@ "serverName": { "value": "[parameters('name')]" }, - "serverKeyType": "[if(contains(parameters('keys')[copyIndex()], 'serverKeyType'), createObject('value', parameters('keys')[copyIndex()].serverKeyType), createObject('value', 'ServiceManaged'))]", - "uri": "[if(contains(parameters('keys')[copyIndex()], 'uri'), createObject('value', parameters('keys')[copyIndex()].uri), createObject('value', ''))]" + "serverKeyType": { + "value": "[coalesce(tryGet(parameters('keys')[copyIndex()], 'serverKeyType'), 'ServiceManaged')]" + }, + "uri": { + "value": "[coalesce(tryGet(parameters('keys')[copyIndex()], 'uri'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -3142,8 +3268,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "17839617504395216689" + "version": "0.29.47.4906", + "templateHash": "5863771213375512760" }, "name": "Azure SQL Server Keys", "description": "This module deploys an Azure SQL Server Key.", @@ -3252,8 +3378,12 @@ "serverKeyName": { "value": "[parameters('encryptionProtectorObj').serverKeyName]" }, - "serverKeyType": "[if(contains(parameters('encryptionProtectorObj'), 'serverKeyType'), createObject('value', parameters('encryptionProtectorObj').serverKeyType), createObject('value', 'ServiceManaged'))]", - "autoRotationEnabled": "[if(contains(parameters('encryptionProtectorObj'), 'autoRotationEnabled'), createObject('value', parameters('encryptionProtectorObj').autoRotationEnabled), createObject('value', true()))]" + "serverKeyType": { + "value": "[coalesce(tryGet(parameters('encryptionProtectorObj'), 'serverKeyType'), 'ServiceManaged')]" + }, + "autoRotationEnabled": { + "value": "[coalesce(tryGet(parameters('encryptionProtectorObj'), 'autoRotationEnabled'), true())]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -3261,8 +3391,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "11473914706327458055" + "version": "0.29.47.4906", + "templateHash": "6914924378490463775" }, "name": "Azure SQL Server Encryption Protector", "description": "This module deploys an Azure SQL Server Encryption Protector.", @@ -3394,8 +3524,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "2456263707393734456" + "version": "0.29.47.4906", + "templateHash": "4165841300638093382" }, "name": "Azure SQL Server Audit Settings", "description": "This module deploys an Azure SQL Server Audit Settings.", @@ -3533,8 +3663,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "13956215614091387428" + "version": "0.29.47.4906", + "templateHash": "17251889896692066430" } }, "parameters": { @@ -3621,8 +3751,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "16142913599202614386" + "version": "0.29.47.4906", + "templateHash": "594547303316002116" } }, "definitions": { diff --git a/avm/res/sql/server/tests/e2e/max/main.test.bicep b/avm/res/sql/server/tests/e2e/max/main.test.bicep index ec70abad1a..e95f51ae35 100644 --- a/avm/res/sql/server/tests/e2e/max/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/max/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-sql.servers-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Enforce uksouth to avoid restrictions around zone redundancy in certain regions +#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 = 'sqlsmax' @@ -32,17 +33,17 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: resourceLocation + location: enforcedLocation } } @@ -50,13 +51,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}azsa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: resourceLocation + location: enforcedLocation } } @@ -66,7 +67,7 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' params: { name: '${namePrefix}-${serviceShort}' lock: { @@ -76,7 +77,7 @@ module testDeployment '../../../main.bicep' = { primaryUserAssignedIdentityId: nestedDependencies.outputs.managedIdentityResourceId administratorLogin: 'adminUserName' administratorLoginPassword: password - location: resourceLocation + location: enforcedLocation roleAssignments: [ { name: '7027a5c5-d1b1-49e0-80cc-ffdff3a3ada9' @@ -115,8 +116,6 @@ module testDeployment '../../../main.bicep' = { skuName: 'GP_Gen5' skuTier: 'GeneralPurpose' skuCapacity: 10 - // Pre-existing 'public' configuration - maintenanceConfigurationId: '${subscription().id}/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_${resourceLocation}_DB_1' } ] databases: [ diff --git a/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep b/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep index 2f7e279f3b..3777c51c2c 100644 --- a/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-sql.servers-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Enforce uksouth to avoid restrictions around zone redundancy in certain regions +#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 = 'sqlswaf' @@ -28,17 +29,17 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: resourceLocation + location: enforcedLocation } } @@ -46,13 +47,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}azsa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: resourceLocation + location: enforcedLocation } } @@ -62,7 +63,7 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' params: { name: '${namePrefix}-${serviceShort}' primaryUserAssignedIdentityId: nestedDependencies.outputs.managedIdentityResourceId @@ -73,7 +74,7 @@ module testDeployment '../../../main.bicep' = { principalType: 'Application' tenantId: tenant().tenantId } - location: resourceLocation + location: enforcedLocation vulnerabilityAssessmentsObj: { name: 'default' emailSubscriptionAdmins: true @@ -90,8 +91,7 @@ module testDeployment '../../../main.bicep' = { skuName: 'GP_Gen5' skuTier: 'GeneralPurpose' skuCapacity: 10 - // Pre-existing 'public' configuration - maintenanceConfigurationId: '${subscription().id}/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_${resourceLocation}_DB_1' + maintenanceConfigurationId: '${subscription().id}/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_${enforcedLocation}_DB_1' } ] databases: [ diff --git a/avm/res/sql/server/version.json b/avm/res/sql/server/version.json index 0f81d22abc..b8b30a0125 100644 --- a/avm/res/sql/server/version.json +++ b/avm/res/sql/server/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.8", + "version": "0.9", "pathFilters": [ "./main.json" ] From 797475cd40db2fd31897b4422bb85a2c0bb7f77b Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 14 Oct 2024 00:25:46 +0200 Subject: [PATCH 75/93] fix: Added `Microsoft.DevOpsInfrastructure/pools` to removal order (#3516) ## Description After observing [a few times](https://github.com/Azure/bicep-registry-modules/actions/runs/11297815667/job/31425540661#step:4:887) that the removal job for the module `Microsoft.DevOpsInfrastructure/pools` failed, I figured it is time to add it to the removal order. The error usually happens when the removal logic tries to remove the RG before the Pool - presumably because it breaks the resource's dependencies (e.g., its VNET) and in turn leaves the resource also in a broken, unremovable state. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.dev-ops-infrastructure.pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml/badge.svg?branch=users%2Falsehr%2FmanagedDevOpsRemovalORder&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml) | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- .../resourceRemoval/Initialize-DeploymentRemoval.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 index 32ef457548..a4a98b8e2d 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/Initialize-DeploymentRemoval.ps1 @@ -94,6 +94,7 @@ function Initialize-DeploymentRemoval { 'Microsoft.ContainerInstance/containerGroups' # Must be removed before their MSI 'Microsoft.ManagedIdentity/userAssignedIdentities', 'Microsoft.Databricks/workspaces' + 'Microsoft.DevOpsInfrastructure/pools' # Must be removed before other resources it depends on like a virtual network 'Microsoft.Resources/resourceGroups' ) From 2e27126834e33f8f6bcf8def57ff7632506d2ae5 Mon Sep 17 00:00:00 2001 From: "Menghua Chen (MSFT)" <111940661+Menghua1@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:16:17 +0800 Subject: [PATCH 76/93] feat: Add new ptn modules `avm/ptn/azd/ml-ai-environment` (#3262) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1229. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-ai-environment](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-ai-environment.yml/badge.svg?branch=ml-ai-environment)](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-ai-environment.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.ptn.azd.ml-ai-environment.yml | 88 + avm/ptn/azd/ml-ai-environment/README.md | 545 + avm/ptn/azd/ml-ai-environment/main.bicep | 187 + avm/ptn/azd/ml-ai-environment/main.json | 30513 ++++++++++++++++ .../azd/ml-ai-environment/modules/hub.bicep | 132 + .../tests/e2e/defaults/main.test.bicep | 55 + .../tests/e2e/max/main.test.bicep | 73 + avm/ptn/azd/ml-ai-environment/version.json | 7 + 10 files changed, 31602 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.ml-ai-environment.yml create mode 100644 avm/ptn/azd/ml-ai-environment/README.md create mode 100644 avm/ptn/azd/ml-ai-environment/main.bicep create mode 100644 avm/ptn/azd/ml-ai-environment/main.json create mode 100644 avm/ptn/azd/ml-ai-environment/modules/hub.bicep create mode 100644 avm/ptn/azd/ml-ai-environment/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep create mode 100644 avm/ptn/azd/ml-ai-environment/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 07a798c38d..34070f3b2b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -18,6 +18,7 @@ /avm/ptn/azd/container-app-upsert/ @Azure/avm-ptn-azd-containerappupsert-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/ml-ai-environment/ @Azure/avm-ptn-azd-mlaienvironment-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-project/ @Azure/avm-ptn-azd-mlproject-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/monitoring/ @Azure/avm-ptn-azd-monitoring-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 4fdaa41ac2..56d3fb70d3 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -53,6 +53,7 @@ body: - "avm/ptn/azd/container-app-upsert" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" + - "avm/ptn/azd/ml-ai-environment" - "avm/ptn/azd/ml-hub-dependencies" - "avm/ptn/azd/ml-project" - "avm/ptn/azd/monitoring" diff --git a/.github/workflows/avm.ptn.azd.ml-ai-environment.yml b/.github/workflows/avm.ptn.azd.ml-ai-environment.yml new file mode 100644 index 0000000000..2bf27870e8 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.ml-ai-environment.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.ml-ai-environment" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.ml-ai-environment" + - "avm/ptn/azd/ml-ai-environment/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/ml-ai-environment" + workflowPath: ".github/workflows/avm.ptn.azd.ml-ai-environment.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit \ No newline at end of file diff --git a/avm/ptn/azd/ml-ai-environment/README.md b/avm/ptn/azd/ml-ai-environment/README.md new file mode 100644 index 0000000000..3dd9ecfc56 --- /dev/null +++ b/avm/ptn/azd/ml-ai-environment/README.md @@ -0,0 +1,545 @@ +# Azd Azure Machine Learning Environment `[Azd/MlAiEnvironment]` + +Create Azure Machine Learning workspaces of type 'Hub' and 'Project' and their required dependencies. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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.CognitiveServices/accounts` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts) | +| `Microsoft.CognitiveServices/accounts/deployments` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts/deployments) | +| `Microsoft.ContainerRegistry/registries` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries) | +| `Microsoft.ContainerRegistry/registries/cacheRules` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/cacheRules) | +| `Microsoft.ContainerRegistry/registries/credentialSets` | [2023-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/credentialSets) | +| `Microsoft.ContainerRegistry/registries/replications` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/replications) | +| `Microsoft.ContainerRegistry/registries/scopeMaps` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/scopeMaps) | +| `Microsoft.ContainerRegistry/registries/webhooks` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/webhooks) | +| `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) | +| `Microsoft.KeyVault/vaults` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults) | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-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.MachineLearningServices/workspaces` | [2024-04-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01-preview/workspaces) | +| `Microsoft.MachineLearningServices/workspaces/computes` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2022-10-01/workspaces/computes) | +| `Microsoft.MachineLearningServices/workspaces/connections` | [2024-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01/workspaces/connections) | +| `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) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-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.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.OperationalInsights/workspaces` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-01/workspaces) | +| `Microsoft.OperationalInsights/workspaces/dataExports` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataExports) | +| `Microsoft.OperationalInsights/workspaces/dataSources` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataSources) | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedServices) | +| `Microsoft.OperationalInsights/workspaces/linkedStorageAccounts` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedStorageAccounts) | +| `Microsoft.OperationalInsights/workspaces/savedSearches` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/savedSearches) | +| `Microsoft.OperationalInsights/workspaces/storageInsightConfigs` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/storageInsightConfigs) | +| `Microsoft.OperationalInsights/workspaces/tables` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-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.Portal/dashboards` | [2020-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Portal/2020-09-01-preview/dashboards) | +| `Microsoft.Search/searchServices` | [2024-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2024-03-01-preview/searchServices) | +| `Microsoft.Search/searchServices/sharedPrivateLinkResources` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2023-11-01/searchServices/sharedPrivateLinkResources) | +| `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-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/ptn/azd/ml-ai-environment:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module mlAiEnvironment 'br/public:avm/ptn/azd/ml-ai-environment:' = { + name: 'mlAiEnvironmentDeployment' + params: { + // Required parameters + cognitiveServicesName: 'maemincs001' + hubName: 'maeminhub001' + keyVaultName: 'maeminkv00' + openAiConnectionName: 'maeminai001-connection' + projectName: 'maeminpro001' + searchConnectionName: 'maeminsearch001-connection' + storageAccountName: 'maeminsa001' + userAssignedtName: 'maeminua001' + // 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 + "cognitiveServicesName": { + "value": "maemincs001" + }, + "hubName": { + "value": "maeminhub001" + }, + "keyVaultName": { + "value": "maeminkv00" + }, + "openAiConnectionName": { + "value": "maeminai001-connection" + }, + "projectName": { + "value": "maeminpro001" + }, + "searchConnectionName": { + "value": "maeminsearch001-connection" + }, + "storageAccountName": { + "value": "maeminsa001" + }, + "userAssignedtName": { + "value": "maeminua001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-ai-environment:' + +// Required parameters +param cognitiveServicesName = 'maemincs001' +param hubName = 'maeminhub001' +param keyVaultName = 'maeminkv00' +param openAiConnectionName = 'maeminai001-connection' +param projectName = 'maeminpro001' +param searchConnectionName = 'maeminsearch001-connection' +param storageAccountName = 'maeminsa001' +param userAssignedtName = 'maeminua001' +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 2: _Using large parameter set_ + +This instance deploys the module using large parameters. + + +

    + +via Bicep module + +```bicep +module mlAiEnvironment 'br/public:avm/ptn/azd/ml-ai-environment:' = { + name: 'mlAiEnvironmentDeployment' + params: { + // Required parameters + cognitiveServicesName: 'maemaxcs001' + hubName: 'maemaxhub001' + keyVaultName: 'maemaxkv001' + openAiConnectionName: 'maemaxai001-connection' + projectName: 'maemaxpro001' + searchConnectionName: 'maemaxsearch001-connection' + storageAccountName: 'maemaxsta001' + userAssignedtName: 'maemaxua001' + // Non-required parameters + applicationInsightsName: 'maemaxappin001' + cognitiveServicesDeployments: [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0613' + } + name: 'gpt-35-turbo' + sku: { + capacity: 20 + name: 'Standard' + } + } + ] + containerRegistryName: 'maemaxcr001' + location: '' + logAnalyticsName: 'maemaxla001' + searchServiceName: 'maemaxsearch001' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "cognitiveServicesName": { + "value": "maemaxcs001" + }, + "hubName": { + "value": "maemaxhub001" + }, + "keyVaultName": { + "value": "maemaxkv001" + }, + "openAiConnectionName": { + "value": "maemaxai001-connection" + }, + "projectName": { + "value": "maemaxpro001" + }, + "searchConnectionName": { + "value": "maemaxsearch001-connection" + }, + "storageAccountName": { + "value": "maemaxsta001" + }, + "userAssignedtName": { + "value": "maemaxua001" + }, + // Non-required parameters + "applicationInsightsName": { + "value": "maemaxappin001" + }, + "cognitiveServicesDeployments": { + "value": [ + { + "model": { + "format": "OpenAI", + "name": "gpt-35-turbo", + "version": "0613" + }, + "name": "gpt-35-turbo", + "sku": { + "capacity": 20, + "name": "Standard" + } + } + ] + }, + "containerRegistryName": { + "value": "maemaxcr001" + }, + "location": { + "value": "" + }, + "logAnalyticsName": { + "value": "maemaxla001" + }, + "searchServiceName": { + "value": "maemaxsearch001" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-ai-environment:' + +// Required parameters +param cognitiveServicesName = 'maemaxcs001' +param hubName = 'maemaxhub001' +param keyVaultName = 'maemaxkv001' +param openAiConnectionName = 'maemaxai001-connection' +param projectName = 'maemaxpro001' +param searchConnectionName = 'maemaxsearch001-connection' +param storageAccountName = 'maemaxsta001' +param userAssignedtName = 'maemaxua001' +// Non-required parameters +param applicationInsightsName = 'maemaxappin001' +param cognitiveServicesDeployments = [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0613' + } + name: 'gpt-35-turbo' + sku: { + capacity: 20 + name: 'Standard' + } + } +] +param containerRegistryName = 'maemaxcr001' +param location = '' +param logAnalyticsName = 'maemaxla001' +param searchServiceName = 'maemaxsearch001' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cognitiveServicesName`](#parameter-cognitiveservicesname) | string | The Cognitive Services name. | +| [`hubName`](#parameter-hubname) | string | The AI Studio Hub Resource name. | +| [`keyVaultName`](#parameter-keyvaultname) | string | The Key Vault resource name. | +| [`projectName`](#parameter-projectname) | string | The AI Project resource name. | +| [`storageAccountName`](#parameter-storageaccountname) | string | The Storage Account resource name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationInsightsName`](#parameter-applicationinsightsname) | string | The Application Insights resource name. | +| [`cognitiveServicesDeployments`](#parameter-cognitiveservicesdeployments) | array | Array of deployments about cognitive service accounts to create. | +| [`containerRegistryName`](#parameter-containerregistryname) | string | The Container Registry resource name. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`logAnalyticsName`](#parameter-loganalyticsname) | string | The Log Analytics resource name. | +| [`openAiConnectionName`](#parameter-openaiconnectionname) | string | The Open AI connection name. | +| [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. | +| [`searchConnectionName`](#parameter-searchconnectionname) | string | The Azure Search connection name. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`userAssignedtName`](#parameter-userassignedtname) | string | The User Assigned Identity resource name. | + +**Condition parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`searchServiceName`](#parameter-searchservicename) | string | The Azure Search resource name. Required if the parameter searchServiceName is not empty. | + +### Parameter: `cognitiveServicesName` + +The Cognitive Services name. + +- Required: Yes +- Type: string + +### Parameter: `hubName` + +The AI Studio Hub Resource name. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +The Key Vault resource name. + +- Required: Yes +- Type: string + +### Parameter: `projectName` + +The AI Project resource name. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +The Storage Account resource name. + +- Required: Yes +- Type: string + +### Parameter: `applicationInsightsName` + +The Application Insights resource name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `cognitiveServicesDeployments` + +Array of deployments about cognitive service accounts to create. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `containerRegistryName` + +The Container Registry resource name. + +- 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: `logAnalyticsName` + +The Log Analytics resource name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `openAiConnectionName` + +The Open AI connection name. + +- Required: Yes +- Type: string + +### Parameter: `replicaCount` + +The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `searchConnectionName` + +The Azure Search connection name. + +- Required: Yes +- Type: string + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + "key1": "value1" + "key2": "value2" + } + ``` + +### Parameter: `userAssignedtName` + +The User Assigned Identity resource name. + +- Required: Yes +- Type: string + +### Parameter: `searchServiceName` + +The Azure Search resource name. Required if the parameter searchServiceName is not empty. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `applicationInsightsName` | string | The name of the application insights. | +| `containerRegistryEndpoint` | string | The endpoint of the container registry. | +| `containerRegistryName` | string | The name of the container registry. | +| `hubName` | string | The name of the ai studio hub. | +| `hubPrincipalId` | string | The principal ID of the ai studio hub. | +| `keyVaultEndpoint` | string | The endpoint of the key vault. | +| `keyVaultName` | string | The name of the key vault. | +| `logAnalyticsWorkspaceName` | string | The name of the log analytics workspace. | +| `openAiEndpoint` | string | The endpoint of the cognitive services. | +| `openAiName` | string | The name of the cognitive services. | +| `projectName` | string | The name of the ai studio project. | +| `projectPrincipalId` | string | The principal ID of the ai studio project. | +| `resourceGroupName` | string | The name of the resource group the module was deployed to. | +| `searchServiceEndpoint` | string | The endpoint of the search service. | +| `searchServiceName` | string | The name of the search service. | +| `storageAccountName` | string | The name of the storage 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/ptn/azd/ml-hub-dependencies:0.1.0` | Remote reference | +| `br/public:avm/ptn/azd/ml-project:0.1.0` | Remote reference | +| `br/public:avm/res/machine-learning-services/workspace:0.8.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/ptn/azd/ml-ai-environment/main.bicep b/avm/ptn/azd/ml-ai-environment/main.bicep new file mode 100644 index 0000000000..97dcd25920 --- /dev/null +++ b/avm/ptn/azd/ml-ai-environment/main.bicep @@ -0,0 +1,187 @@ +metadata name = 'Azd Azure Machine Learning Environment' +metadata description = '''Create Azure Machine Learning workspaces of type 'Hub' and 'Project' and their required dependencies. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The AI Studio Hub Resource name.') +param hubName string + +@description('Required. The AI Project resource name.') +param projectName string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +@description('Optional. The Container Registry resource name.') +param containerRegistryName string = '' + +@description('Required. The Cognitive Services name.') +param cognitiveServicesName string + +@description('Required. The Key Vault resource name.') +param keyVaultName string + +@description('Required. The Storage Account resource name.') +param storageAccountName string + +@description('Optional. The Application Insights resource name.') +param applicationInsightsName string = '' + +@description('Optional. The Log Analytics resource name.') +param logAnalyticsName string = '' + +@description('Optional. Array of deployments about cognitive service accounts to create.') +param cognitiveServicesDeployments array = [] + +@description('Condition. The Azure Search resource name. Required if the parameter searchServiceName is not empty.') +param searchServiceName string = '' + +@description('Optional. The Open AI connection name.') +param openAiConnectionName string + +@description('Optional. The Azure Search connection name.') +param searchConnectionName string + +@description('Optional. The User Assigned Identity resource name.') +param userAssignedtName string + +@description('Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU.') +@minValue(1) +@maxValue(12) +param replicaCount int = 1 + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-mlaienvironment.${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 hubDependencies 'br/public:avm/ptn/azd/ml-hub-dependencies:0.1.0' = { + name: '${uniqueString(deployment().name, location)}-mlHubDependenciesDeployment' + params: { + location: location + tags: tags + cognitiveServicesName: cognitiveServicesName + keyVaultName: keyVaultName + storageAccountName: storageAccountName + applicationInsightsName: applicationInsightsName + logAnalyticsName: logAnalyticsName + containerRegistryName: containerRegistryName + cognitiveServicesDeployments: cognitiveServicesDeployments + searchServiceName: searchServiceName + replicaCount: replicaCount + enableTelemetry: enableTelemetry + } +} + +module hub './modules/hub.bicep' = { + name: '${uniqueString(deployment().name, location)}-hub' + params: { + location: location + tags: tags + name: hubName + keyVaultResourceId: hubDependencies.outputs.keyVaultResourceId + storageAccountResourceId: hubDependencies.outputs.storageAccountResourceId + containerRegistryResourceId: hubDependencies.outputs.containerRegistryResourceId + applicationInsightsResourceId: hubDependencies.outputs.applicationInsightsResourceId + openAiName: hubDependencies.outputs.cognitiveServicesName + aiSearchName: hubDependencies.outputs.searchServiceName + aiSearchConnectionName: searchConnectionName + openAiContentSafetyConnectionName: openAiConnectionName + } +} + +module project 'br/public:avm/ptn/azd/ml-project:0.1.0' = { + name: '${uniqueString(deployment().name, location)}-project' + params: { + name: projectName + hubResourceId: hub.outputs.resourceId + keyVaultName: hubDependencies.outputs.keyVaultName + userAssignedName: userAssignedtName + enableTelemetry: enableTelemetry + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The name of the resource group the module was deployed to.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the ai studio hub.') +output hubName string = hub.outputs.name + +@description('The principal ID of the ai studio hub.') +output hubPrincipalId string = hub.outputs.principalId + +@description('The name of the ai studio project.') +output projectName string = project.outputs.projectName + +@description('The principal ID of the ai studio project.') +output projectPrincipalId string = project.outputs.projectPrincipalId + +@description('The name of the key vault.') +output keyVaultName string = hubDependencies.outputs.keyVaultName + +@description('The endpoint of the key vault.') +output keyVaultEndpoint string = hubDependencies.outputs.keyVaultEndpoint + +@description('The name of the application insights.') +output applicationInsightsName string = hubDependencies.outputs.applicationInsightsName + +@description('The name of the log analytics workspace.') +output logAnalyticsWorkspaceName string = hubDependencies.outputs.logAnalyticsWorkspaceName + +@description('The name of the container registry.') +output containerRegistryName string = hubDependencies.outputs.containerRegistryName + +@description('The endpoint of the container registry.') +output containerRegistryEndpoint string = hubDependencies.outputs.containerRegistryEndpoint + +@description('The name of the storage account.') +output storageAccountName string = hubDependencies.outputs.storageAccountName + +@description('The name of the cognitive services.') +output openAiName string = hubDependencies.outputs.cognitiveServicesName + +@description('The endpoint of the cognitive services.') +output openAiEndpoint string = hubDependencies.outputs.cognitiveServicesEndpoint + +@description('The name of the search service.') +output searchServiceName string = hubDependencies.outputs.searchServiceName + +@description('The endpoint of the search service.') +output searchServiceEndpoint string = hubDependencies.outputs.searchServiceEndpoint diff --git a/avm/ptn/azd/ml-ai-environment/main.json b/avm/ptn/azd/ml-ai-environment/main.json new file mode 100644 index 0000000000..cb3b56312e --- /dev/null +++ b/avm/ptn/azd/ml-ai-environment/main.json @@ -0,0 +1,30513 @@ +{ + "$schema": "https://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": "149833058937281725" + }, + "name": "Azd Azure Machine Learning Environment", + "description": "Create Azure Machine Learning workspaces of type 'Hub' and 'Project' and their required dependencies.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "hubName": { + "type": "string", + "metadata": { + "description": "Required. The AI Studio Hub Resource name." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Required. The AI Project resource name." + } + }, + "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." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Container Registry resource name." + } + }, + "cognitiveServicesName": { + "type": "string", + "metadata": { + "description": "Required. The Cognitive Services name." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The Key Vault resource name." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. The Storage Account resource name." + } + }, + "applicationInsightsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Application Insights resource name." + } + }, + "logAnalyticsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Log Analytics resource name." + } + }, + "cognitiveServicesDeployments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "searchServiceName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Condition. The Azure Search resource name. Required if the parameter searchServiceName is not empty." + } + }, + "openAiConnectionName": { + "type": "string", + "metadata": { + "description": "Optional. The Open AI connection name." + } + }, + "searchConnectionName": { + "type": "string", + "metadata": { + "description": "Optional. The Azure Search connection name." + } + }, + "userAssignedtName": { + "type": "string", + "metadata": { + "description": "Optional. The User Assigned Identity resource name." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-mlaienvironment.{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" + } + } + } + } + }, + "hubDependencies": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-mlHubDependenciesDeployment', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "cognitiveServicesName": { + "value": "[parameters('cognitiveServicesName')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "applicationInsightsName": { + "value": "[parameters('applicationInsightsName')]" + }, + "logAnalyticsName": { + "value": "[parameters('logAnalyticsName')]" + }, + "containerRegistryName": { + "value": "[parameters('containerRegistryName')]" + }, + "cognitiveServicesDeployments": { + "value": "[parameters('cognitiveServicesDeployments')]" + }, + "searchServiceName": { + "value": "[parameters('searchServiceName')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "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": "11541059920638838548" + }, + "name": "Azd Azure Machine Learning Dependencies", + "description": "Creates all the dependencies required for a Machine Learning Service.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "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. Required if a user assigned identity is used for encryption." + } + } + }, + "nullable": true + } + }, + "parameters": { + "applicationInsightsDashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "applicationInsightsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource insights components name." + } + }, + "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." + } + }, + "logAnalyticsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource operational insights workspaces name." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. Name of the key vault." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Name of the storage account." + } + }, + "cognitiveServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the OpenAI cognitive services." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the container registry." + } + }, + "searchServiceName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the Azure Cognitive Search service." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": 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." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint in the storage account. 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." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for the storage account. 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." + } + }, + "networkAcls": { + "type": "object", + "defaultValue": { + "bypass": "AzureServices", + "defaultAction": "Allow" + }, + "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." + } + }, + "blobServices": { + "type": "object", + "defaultValue": { + "containers": [ + { + "name": "default" + } + ], + "corsRules": [ + { + "allowedOrigins": [ + "https://mlworkspace.azure.ai", + "https://ml.azure.com", + "https://*.ml.azure.com", + "https://ai.azure.com", + "https://*.ai.azure.com", + "https://mlworkspacecanary.azure.ai", + "https://mlworkspace.azureml-test.net" + ], + "allowedMethods": [ + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "OPTIONS", + "PATCH" + ], + "maxAgeInSeconds": 1800, + "exposedHeaders": [ + "*" + ], + "allowedHeaders": [ + "*" + ] + } + ], + "deleteRetentionPolicyEnabled": true, + "containerDeleteRetentionPolicyDays": 7, + "deleteRetentionPolicyDays": 6, + "deleteRetentionPolicyAllowPermanentDelete": true + }, + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + }, + "cognitiveServicesKind": { + "type": "string", + "defaultValue": "AIServices", + "metadata": { + "description": "Optional. Kind of the Cognitive Services." + } + }, + "cognitiveServicesDeployments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "cognitiveServicesCustomSubDomainName": { + "type": "string", + "defaultValue": "[parameters('cognitiveServicesName')]", + "metadata": { + "description": "Optional. The custom subdomain name used to access the API. Defaults to the value of the name parameter." + } + }, + "cognitiveServicesDisableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "cognitiveServicesPublicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "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." + } + }, + "cognitiveServicesNetworkAcls": { + "type": "object", + "defaultValue": { + "defaultAction": "Allow" + }, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "cognitiveServicesSku": { + "type": "string", + "defaultValue": "S0", + "metadata": { + "description": "Optional. SKU of the Cognitive Services resource." + } + }, + "registryAcrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "registryPublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Optional. Public network access setting." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": false, + "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." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "keyVaultSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "logAnalyticsSkuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 30, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "authOptions": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default", + "highDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "networkRuleSet": { + "type": "object", + "defaultValue": { + "bypass": "None", + "ipRules": [] + }, + "metadata": { + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "searchServicePublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "searchServiceSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "nullable": true, + "metadata": { + "description": "Conditional. The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-mlhubdependencies.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableRbacAuthorization": { + "value": "[parameters('enableRbacAuthorization')]" + }, + "enableVaultForDeployment": { + "value": "[parameters('enableVaultForDeployment')]" + }, + "enableVaultForTemplateDeployment": { + "value": "[parameters('enableVaultForTemplateDeployment')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "sku": { + "value": "[parameters('keyVaultSku')]" + }, + "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.29.47.4906", + "templateHash": "6878673228466609441" + }, + "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": { + "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." + } + }, + "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": "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 (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.keyvault-vault.{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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "7494731697751039419" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "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.29.47.4906", + "templateHash": "4990258423482296566" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "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 + } + }, + "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": { + "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 (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')]" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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'))]" + }, + "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.29.47.4906", + "templateHash": "10436564794447478489" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "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 + } + }, + "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": { + "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 (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())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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": { + "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], '2020-06-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]" + } + } + } + } + }, + "storageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-storage', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": "[parameters('allowBlobPublicAccess')]" + }, + "dnsEndpointType": { + "value": "[parameters('dnsEndpointType')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "networkAcls": { + "value": "[parameters('networkAcls')]" + }, + "blobServices": { + "value": "[parameters('blobServices')]" + }, + "fileServices": { + "value": "[parameters('fileServices')]" + }, + "queueServices": { + "value": "[parameters('queueServices')]" + }, + "tableServices": { + "value": "[parameters('tableServices')]" + }, + "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.28.1.47646", + "templateHash": "3958760216991467865" + }, + "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 + }, + "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": { + "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 + }, + "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." + } + }, + "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." + } + } + } + }, + "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." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "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." + } + }, + "localUsers": { + "type": "array", + "defaultValue": [], + "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": { + "$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." + } + }, + "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())]", + "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 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 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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.9.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" + } + } + } + } + }, + "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'))), 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", + "cMKUserAssignedIdentity" + ] + }, + "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(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts', 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": [ + "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], '2020-06-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": [ + "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.28.1.47646", + "templateHash": "9473195527943694039" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy.", + "owner": "Azure/module-maintainers" + }, + "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(parameters('localUsers'))]" + }, + "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": "[parameters('localUsers')[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[parameters('localUsers')[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[parameters('localUsers')[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[parameters('localUsers')[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(parameters('localUsers')[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.28.1.47646", + "templateHash": "14968464858285923305" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "sshAuthorizedKeysType": { + "type": "secureObject", + "properties": { + "secureList": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "string", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + } + }, + "metadata": { + "description": "Optional. The list of SSH authorized keys." + } + } + }, + "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", + "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", + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "$ref": "#/definitions/sshAuthorizedKeysType", + "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": "[tryGet(parameters('sshAuthorizedKeys'), 'secureList')]" + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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.28.1.47646", + "templateHash": "2306287879023715578" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob 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." + } + }, + "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", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies CORS rules for the Blob service. You can include up to five CorsRule elements in the request. If no CorsRule elements are included in the request body, all CORS rules will be deleted, and CORS will be disabled for the Blob service." + } + }, + "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": 6, + "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": { + "$ref": "#/definitions/diagnosticSettingType", + "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": { + "corsRules": "[parameters('corsRules')]" + }, + "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')]" + }, + "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.28.1.47646", + "templateHash": "7045309160947869799" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container.", + "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." + } + }, + "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", + "defaultValue": false, + "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": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "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')]", + "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 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'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "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'), 'default', parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", + "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')]" + }, + "dependsOn": [ + "storageAccount::blobServices" + ] + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', 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": [ + "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.28.1.47646", + "templateHash": "2543276032744560941" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy.", + "owner": "Azure/module-maintainers" + }, + "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", + "storageAccount" + ] + } + }, + "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'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "7463227074634701879" + }, + "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')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "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.28.1.47646", + "templateHash": "1342480740201032357" + }, + "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'))]", + "dependsOn": [ + "storageAccount" + ] + }, + "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')]" + }, + "dependsOn": [ + "storageAccount::fileService" + ] + }, + "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.28.1.47646", + "templateHash": "8779226603522513073" + } + }, + "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" + ] + }, + "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')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "10678250016540336570" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue 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." + } + }, + "queues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "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": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "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.28.1.47646", + "templateHash": "13487964166280180730" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue.", + "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." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Required. A name-value pair that represents queue metadata." + } + }, + "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')]", + "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 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')]", + "dependsOn": [ + "storageAccount" + ] + }, + "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')]" + }, + "dependsOn": [ + "storageAccount::queueServices" + ] + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), 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": "[guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', 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": [ + "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]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "16839054392438941735" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table 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." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. tables to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "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": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "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.28.1.47646", + "templateHash": "3177845984945141330" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table.", + "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." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "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')]", + "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 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')]", + "dependsOn": [ + "storageAccount" + ] + }, + "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'))]", + "dependsOn": [ + "storageAccount::tableServices" + ] + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), 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": "[guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', 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": [ + "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]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "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" + ] + } + }, + "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]" + } + } + } + } + }, + "cognitiveServices": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cognitive', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('cognitiveServicesName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('cognitiveServicesKind')]" + }, + "customSubDomainName": { + "value": "[parameters('cognitiveServicesCustomSubDomainName')]" + }, + "publicNetworkAccess": { + "value": "[parameters('cognitiveServicesPublicNetworkAccess')]" + }, + "networkAcls": { + "value": "[parameters('cognitiveServicesNetworkAcls')]" + }, + "disableLocalAuth": { + "value": "[parameters('cognitiveServicesDisableLocalAuth')]" + }, + "sku": { + "value": "[parameters('cognitiveServicesSku')]" + }, + "deployments": { + "value": "[parameters('cognitiveServicesDeployments')]" + }, + "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.29.47.4906", + "templateHash": "7976342392137470716" + }, + "name": "Cognitive Services", + "description": "This module deploys a Cognitive 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 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 + }, + "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 + }, + "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. Required if a user assigned identity is used for encryption." + } + } + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "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 + }, + "deploymentsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + } + } + }, + "nullable": true + }, + "endpointsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "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." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "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." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "$ref": "#/definitions/deploymentsType", + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts 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', 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": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "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')]" + } + }, + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('0.7.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" + } + } + } + } + }, + "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'), '/'))]" + }, + "cognitiveService": { + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2023-05-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2023-05-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku')))]", + "dependsOn": [ + "cognitiveService" + ] + }, + "cognitiveService_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.CognitiveServices/accounts/{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": [ + "cognitiveService" + ] + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.CognitiveServices/accounts/{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": [ + "cognitiveService" + ] + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', 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": [ + "cognitiveService" + ] + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cognitiveService-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.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), 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.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), 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.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), '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'))]" + }, + "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.29.47.4906", + "templateHash": "13720311665093076615" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "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 + }, + "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 + } + }, + "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": { + "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.6.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('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.29.47.4906", + "templateHash": "15263454436186512874" + }, + "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-11-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-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "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": [ + "cognitiveService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services account." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The service endpoint of the cognitive services account." + }, + "value": "[reference('cognitiveService').endpoint]" + }, + "endpoints": { + "$ref": "#/definitions/endpointsType", + "metadata": { + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." + }, + "value": "[reference('cognitiveService').endpoints]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('cognitiveService', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('cognitiveService', '2023-05-01', 'full').location]" + } + } + } + } + }, + "logAnalytics": { + "condition": "[not(empty(parameters('logAnalyticsName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-loganalytics', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('logAnalyticsName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": "[parameters('dataRetention')]" + }, + "skuName": { + "value": "[parameters('logAnalyticsSkuName')]" + }, + "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.29.47.4906", + "templateHash": "14441228139596902410" + }, + "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 + }, + "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." + } + }, + "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." + } + } + } + }, + "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." + } + }, + "linkedServices": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "defaultValue": [], + "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", + "defaultValue": [], + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics 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." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "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", + "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)))))]" + } + ], + "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 (Preview)": "[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('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" + } + } + } + } + }, + "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_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_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(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": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'tables')]" + }, + "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.29.47.4906", + "templateHash": "1745671120474305926" + }, + "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]" + } + }, + "dependsOn": [ + "storageAccount", + "workspace" + ] + } + }, + "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(parameters('linkedServices'))]" + }, + "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": "[parameters('linkedServices')[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(parameters('linkedServices')[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(parameters('linkedServices')[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.29.47.4906", + "templateHash": "12032441371027552374" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service.", + "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", + "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'))]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('linkedStorageAccounts'))]" + }, + "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": "[parameters('linkedStorageAccounts')[copyIndex()].name]" + }, + "resourceId": { + "value": "[parameters('linkedStorageAccounts')[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.29.47.4906", + "templateHash": "12623216644328477682" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account.", + "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", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": [ + "[parameters('resourceId')]" + ] + } + } + ], + "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(parameters('savedSearches'))]" + }, + "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}', parameters('savedSearches')[copyIndex()].name, uniqueString(deployment().name))]" + }, + "etag": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[parameters('savedSearches')[copyIndex()].displayName]" + }, + "category": { + "value": "[parameters('savedSearches')[copyIndex()].category]" + }, + "query": { + "value": "[parameters('savedSearches')[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionParameters')]" + }, + "version": { + "value": "[tryGet(parameters('savedSearches')[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.29.47.4906", + "templateHash": "7683333179440464721" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search.", + "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", + "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": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-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')]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('dataExports'))]" + }, + "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": "[parameters('dataExports')[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5765609820817623497" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export.", + "owner": "Azure/module-maintainers" + }, + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2020-08-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(parameters('dataSources'))]" + }, + "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": "[parameters('dataSources')[copyIndex()].name]" + }, + "kind": { + "value": "[parameters('dataSources')[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'performanceCounters')]" + } + }, + "template": { + "$schema": "https://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": "13460038983765020046" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source.", + "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", + "metadata": { + "description": "Required. Name of the solution." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Required. The kind of the DataSource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "linkedResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "defaultValue": "", + "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", + "defaultValue": "", + "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", + "defaultValue": "", + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "defaultValue": "", + "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": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2020-08-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())]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "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(parameters('tables'))]" + }, + "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": "[parameters('tables')[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'searchResults')]" + }, + "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.29.47.4906", + "templateHash": "6905244456918791391" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table.", + "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 + } + }, + "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": { + "type": "object", + "defaultValue": {}, + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "type": "object", + "defaultValue": {}, + "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": { + "$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')]", + "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 (Preview)": "[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": "2022-10-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-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')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "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(parameters('gallerySolutions'))]" + }, + "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": "[parameters('gallerySolutions')[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "product": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'product')]" + }, + "publisher": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'publisher')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('gallerySolutions')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "18444780972506374592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution. For Microsoft published gallery solution the target solution resource name will be composed as `{name}({logAnalyticsWorkspaceName})`." + } + }, + "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." + } + }, + "product": { + "type": "string", + "defaultValue": "OMSGallery", + "metadata": { + "description": "Optional. The product of the deployed solution. For Microsoft published gallery solution it should be `OMSGallery` and the target solution resource product will be composed as `OMSGallery/{name}`. For third party solution, it can be anything. This is case sensitive." + } + }, + "publisher": { + "type": "string", + "defaultValue": "Microsoft", + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "solutionName": "[if(equals(parameters('publisher'), 'Microsoft'), format('{0}({1})', parameters('name'), parameters('logAnalyticsWorkspaceName')), parameters('name'))]", + "solutionProduct": "[if(equals(parameters('publisher'), 'Microsoft'), format('OMSGallery/{0}', parameters('name')), parameters('product'))]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[variables('solutionName')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[variables('solutionName')]", + "promotionCode": "", + "product": "[variables('solutionProduct')]", + "publisher": "[parameters('publisher')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[variables('solutionName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName'))]" + }, + "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(resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName')), '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', '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'), '')]" + } + } + } + } + }, + "applicationInsights": { + "condition": "[and(not(empty(parameters('applicationInsightsName'))), not(empty(parameters('logAnalyticsName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-insights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "name": { + "value": "[parameters('applicationInsightsName')]" + }, + "dashboardName": { + "value": "[parameters('applicationInsightsDashboardName')]" + }, + "logAnalyticsWorkspaceResourceId": "[if(not(empty(parameters('logAnalyticsName'))), createObject('value', reference('logAnalytics').outputs.resourceId.value), createObject('value', ''))]", + "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.29.47.4906", + "templateHash": "17156187352453961206" + }, + "name": "Application Insights Components", + "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "dashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "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." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the loganalytics workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "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." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-insightsdashboard.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "applicationInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appinsights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('kind')]" + }, + "applicationType": { + "value": "[parameters('applicationType')]" + }, + "workspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://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": "10653241142071426932" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance.", + "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 + }, + "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. 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", + "defaultValue": "", + "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." + } + }, + "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." + } + }, + "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." + } + }, + "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')]", + "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('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" + } + } + } + } + }, + "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')]" + } + }, + "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_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": "[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.29.47.4906", + "templateHash": "216781367921725873" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account.", + "owner": "Azure/module-maintainers" + }, + "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]" + } + } + } + } + }, + "applicationInsightsDashboard": { + "condition": "[not(empty(parameters('dashboardName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "application-insights-dashboard", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('dashboardName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "applicationInsightsName": { + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "applicationInsightsResourceId": { + "value": "[reference('applicationInsights').outputs.resourceId.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.29.47.4906", + "templateHash": "9856731218551847403" + }, + "name": "Azure Portal Dashboard", + "description": "Creates a dashboard for an Application Insights instance.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The portal dashboard name." + } + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components ID." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "dashboard": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "dashboard-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "lenses": { + "value": [ + { + "order": 0, + "parts": [ + { + "position": { + "x": 0, + "y": 0, + "colSpan": 2, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "id", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart", + "asset": { + "idInputName": "id", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "overview" + } + }, + { + "position": { + "x": 2, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "ProactiveDetection" + } + }, + { + "position": { + "x": 3, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + } + ], + "type": "Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:20:33.345Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 5, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-08T18:47:35.237Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "ConfigurationId", + "value": "78ce933e-e864-4b05-a27b-71fd55a6afad" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AppMapButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 0, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Usage", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 3, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:22:35.782Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + } + ], + "type": "Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Reliability", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 7, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:42:40.072Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "failures" + } + }, + { + "position": { + "x": 8, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Responsiveness\r\n", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 11, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:43:37.804Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "2a8ede4f-2bee-4b9c-aed9-2db0e8a01865", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "performance" + } + }, + { + "position": { + "x": 12, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Browser", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 15, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "MetricsExplorerJsonDefinitionId", + "value": "BrowserPerformanceTimelineMetrics" + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "createdTime": "2018-05-08T12:16:27.534Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "CurrentFilter", + "value": { + "eventTypes": [ + 4, + 1, + 3, + 5, + 2, + 6, + 13 + ], + "typeFacets": {}, + "isPermissive": false + } + }, + { + "name": "id", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "browser" + } + }, + { + "position": { + "x": 0, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "sessions/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Sessions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "users/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Users", + "color": "#7E58FF" + } + } + ], + "title": "Unique sessions and users", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "segmentationUsers" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Failed requests", + "color": "#EC008C" + } + } + ], + "title": "Failed requests", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "failures" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/duration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server response time", + "color": "#00BCF2" + } + } + ], + "title": "Server response time", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "performance" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/networkDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Page load network connect time", + "color": "#7E58FF" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/processingDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Client processing time", + "color": "#44F1C8" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/sendDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Send request time", + "color": "#EB9371" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/receiveDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Receiving response time", + "color": "#0672F1" + } + } + ], + "title": "Average page load time breakdown", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/availabilityPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability", + "color": "#47BDF5" + } + } + ], + "title": "Average availability", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "availability" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/server", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server exceptions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "dependencies/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Dependency failures", + "color": "#7E58FF" + } + } + ], + "title": "Server exceptions and Dependency failures", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processorCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Processor time", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process CPU", + "color": "#7E58FF" + } + } + ], + "title": "Average processor and process CPU utilization", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/browser", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Browser exceptions", + "color": "#47BDF5" + } + } + ], + "title": "Browser exceptions", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/count", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability test results count", + "color": "#47BDF5" + } + } + ], + "title": "Availability test results count", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processIOBytesPerSecond", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process IO rate", + "color": "#47BDF5" + } + } + ], + "title": "Average process I/O rate", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/memoryAvailableBytes", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Available memory", + "color": "#47BDF5" + } + } + ], + "title": "Average available memory", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "12676032921679464791" + }, + "name": "Portal Dashboards", + "description": "This module deploys a Portal Dashboard.", + "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 + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the dashboard 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." + } + }, + "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." + } + }, + "lenses": { + "type": "array", + "items": { + "type": "object" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The dashboard lenses." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The dashboard metadata." + } + } + }, + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.portal-dashboard.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "dashboard": { + "type": "Microsoft.Portal/dashboards", + "apiVersion": "2020-09-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "lenses": "[parameters('lenses')]", + "metadata": "[parameters('metadata')]" + } + }, + "dashboard_roleAssignments": { + "copy": { + "name": "dashboard_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Portal/dashboards/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Portal/dashboards', 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": [ + "dashboard" + ] + }, + "dashboard_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.Portal/dashboards/{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": [ + "dashboard" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[resourceId('Microsoft.Portal/dashboards', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dashboard was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the dashboard." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the dashboard was deployed into." + }, + "value": "[reference('dashboard', '2020-09-01-preview', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[reference('dashboard').outputs.resourceId.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[reference('dashboard').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "applicationInsights" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights components were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardName.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardResourceId.value, '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[reference('applicationInsights').outputs.connectionString.value]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[reference('applicationInsights').outputs.instrumentationKey.value]" + } + } + } + }, + "dependsOn": [ + "logAnalytics" + ] + }, + "containerRegistry": { + "condition": "[not(empty(parameters('containerRegistryName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('containerRegistryName')]" + }, + "acrSku": { + "value": "[parameters('registryAcrSku')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publicNetworkAccess": { + "value": "[parameters('registryPublicNetworkAccess')]" + }, + "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.29.47.4906", + "templateHash": "8799580877381308457" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR).", + "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 + }, + "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", + "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 + }, + "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 + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "scopeMapsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "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." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registr is enabled or not. Default is enabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "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 networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "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." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "$ref": "#/definitions/scopeMapsType", + "metadata": { + "description": "Optional. Scope maps setting." + } + } + }, + "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": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "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')]" + } + }, + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{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" + } + } + } + } + }, + "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'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(not(empty(parameters('networkRuleSetIpRules'))), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', parameters('networkRuleSetIpRules')), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "registry_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.ContainerRegistry/registries/{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": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerRegistry/registries/{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": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', 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": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "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.29.47.4906", + "templateHash": "9144531012597082524" + }, + "name": "Container Registries scopeMaps", + "description": "This module deploys an Azure Container Registry (ACR) scopeMap.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), 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.29.47.4906", + "templateHash": "8531695368487734118" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "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." + } + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + } + }, + "template": { + "$schema": "https://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": "12196074162662855376" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set.", + "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." + } + } + } + }, + "authCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Required. The managed identity definition for this resource." + } + }, + "authCredentials": { + "$ref": "#/definitions/authCredentialsType", + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "variables": { + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]" + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2023-11-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[variables('identity')]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('credentialSet', '2023-11-01-preview', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name'), replace(replace(coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository, '/', '-'), '.', '-'))]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "4294329625336671928" + }, + "name": "Container Registries Cache", + "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be dereived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action'), createArray('chart_delete', 'chart_push', 'delete', 'push', 'quarantine'))]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), 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.29.47.4906", + "templateHash": "14912363209364245195" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "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." + } + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), 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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), 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.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), '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'))]" + }, + "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": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2019-05-01').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('registry', '2023-06-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2023-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.systemAssignedMIPrincipalId.value]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.resourceId.value]" + } + } + } + } + } + }, + "searchService": { + "condition": "[not(empty(parameters('searchServiceName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchservice', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('searchServiceName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "authOptions": { + "value": "[parameters('authOptions')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "cmkEnforcement": { + "value": "[parameters('cmkEnforcement')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "networkRuleSet": { + "value": "[parameters('networkRuleSet')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "publicNetworkAccess": { + "value": "[parameters('searchServicePublicNetworkAccess')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "sku": { + "value": "[parameters('searchServiceSku')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "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.29.47.4906", + "templateHash": "14924554723661229870" + }, + "name": "Search Services", + "description": "This module deploys a Search Service.", + "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. Required if a user assigned identity is used for encryption." + } + } + }, + "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", + "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": "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 + }, + "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 Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." + } + }, + "authOptions": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default", + "highDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "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." + } + }, + "networkRuleSet": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to help categorize the resource in the Azure portal." + } + } + }, + "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', '')), '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 (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "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.search-searchservice.{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" + } + } + } + } + }, + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2024-03-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "authOptions": "[if(not(empty(parameters('authOptions'))), parameters('authOptions'), null())]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]" + } + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{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": [ + "searchService" + ] + }, + "searchService_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.Search/searchServices/{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": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', 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": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchService-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.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), 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.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), 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.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), '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": [ + "searchService" + ] + }, + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchService-SharedPrivateLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } + }, + "template": { + "$schema": "https://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": "2330033720810948871" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2023-11-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('searchService', '2024-03-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2024-03-01-preview', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the module was deployed to." + }, + "value": "[resourceGroup().name]" + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[reference('keyVault').outputs.resourceId.value]" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[reference('keyVault').outputs.name.value]" + }, + "keyVaultEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the key vault." + }, + "value": "[reference('keyVault').outputs.uri.value]" + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the storage account." + }, + "value": "[reference('storageAccount').outputs.resourceId.value]" + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "The name of the storage account." + }, + "value": "[reference('storageAccount').outputs.name.value]" + }, + "containerRegistryResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.resourceId.value, '')]" + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.name.value, '')]" + }, + "containerRegistryEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.loginServer.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsResourceId.value, '')]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsName.value, '')]" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the loganalytics workspace." + }, + "value": "[if(not(empty(parameters('logAnalyticsName'))), reference('logAnalytics').outputs.resourceId.value, '')]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the loganalytics workspace." + }, + "value": "[if(not(empty(parameters('logAnalyticsName'))), reference('logAnalytics').outputs.name.value, '')]" + }, + "cognitiveServicesResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.resourceId.value]" + }, + "cognitiveServicesName": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.name.value]" + }, + "cognitiveServicesEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.endpoint.value]" + }, + "searchServiceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.resourceId.value, '')]" + }, + "searchServiceName": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.name.value, '')]" + }, + "searchServiceEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), format('https://{0}.search.windows.net/', reference('searchService').outputs.name.value), '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsConnectionString.value, '')]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsInstrumentationKey.value, '')]" + }, + "systemAssignedMiPrincipalId": { + "type": "string", + "metadata": { + "description": "The system assigned mi principal Id key of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.systemAssignedMIPrincipalId.value, '')]" + } + } + } + } + }, + "hub": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-hub', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "name": { + "value": "[parameters('hubName')]" + }, + "keyVaultResourceId": { + "value": "[reference('hubDependencies').outputs.keyVaultResourceId.value]" + }, + "storageAccountResourceId": { + "value": "[reference('hubDependencies').outputs.storageAccountResourceId.value]" + }, + "containerRegistryResourceId": { + "value": "[reference('hubDependencies').outputs.containerRegistryResourceId.value]" + }, + "applicationInsightsResourceId": { + "value": "[reference('hubDependencies').outputs.applicationInsightsResourceId.value]" + }, + "openAiName": { + "value": "[reference('hubDependencies').outputs.cognitiveServicesName.value]" + }, + "aiSearchName": { + "value": "[reference('hubDependencies').outputs.searchServiceName.value]" + }, + "aiSearchConnectionName": { + "value": "[parameters('searchConnectionName')]" + }, + "openAiContentSafetyConnectionName": { + "value": "[parameters('openAiConnectionName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "7726052800082491375" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The AI Studio Hub Resource name." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The storage account ID to use for the AI Studio Hub Resource." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault ID to use for the AI Studio Hub Resource." + } + }, + "applicationInsightsResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The application insights ID to use for the AI Studio Hub Resource." + } + }, + "containerRegistryResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The container registry ID to use for the AI Studio Hub Resource." + } + }, + "openAiName": { + "type": "string", + "metadata": { + "description": "Required. The OpenAI Cognitive Services account name to use for the AI Studio Hub Resource." + } + }, + "aiSearchName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Azure Cognitive Search service name to use for the AI Studio Hub Resource." + } + }, + "aiSearchConnectionName": { + "type": "string", + "metadata": { + "description": "Required. The Azure Cognitive Search service connection name to use for the AI Studio Hub Resource." + } + }, + "openAiContentSafetyConnectionName": { + "type": "string", + "metadata": { + "description": "Required. The OpenAI Content Safety connection name to use for the AI Studio Hub Resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. The SKU name to use for the AI Studio Hub Resource." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The public network access setting to use for the AI Studio Hub Resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "hub-workspace", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "sku": { + "value": "[parameters('skuName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "Hub" + }, + "associatedKeyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "associatedStorageAccountResourceId": { + "value": "[parameters('storageAccountResourceId')]" + }, + "associatedApplicationInsightsResourceId": "[if(not(empty(parameters('applicationInsightsResourceId'))), createObject('value', parameters('applicationInsightsResourceId')), createObject('value', null()))]", + "associatedContainerRegistryResourceId": "[if(not(empty(parameters('containerRegistryResourceId'))), createObject('value', parameters('containerRegistryResourceId')), createObject('value', null()))]", + "hbiWorkspace": { + "value": false + }, + "managedNetworkSettings": { + "value": { + "isolationMode": "Disabled" + } + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "discoveryUrl": { + "value": "[format('https://{0}.api.azureml.ms/discovery', parameters('location'))]" + }, + "connections": { + "value": "[union(createArray(createObject('name', 'aoai-connection', 'category', 'AzureOpenAI', 'isSharedToAll', true(), 'metadata', createObject('ApiVersion', '2024-02-01', 'ApiType', 'azure', 'ResourceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('openAiName'))), 'target', reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('openAiName')), '2023-05-01').endpoints['OpenAI Language Model Instance API'], 'connectionProperties', createObject('authType', 'ApiKey', 'credentials', createObject('key', listKeys(resourceId('Microsoft.CognitiveServices/accounts', parameters('openAiName')), '2023-05-01').key1))), createObject('name', parameters('openAiContentSafetyConnectionName'), 'category', 'AzureOpenAI', 'isSharedToAll', true(), 'target', reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('openAiName')), '2023-05-01').endpoints['Content Safety'], 'metadata', createObject('ApiVersion', '2023-07-01-preview', 'ApiType', 'azure', 'ResourceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('openAiName'))), 'connectionProperties', createObject('authType', 'ApiKey', 'credentials', createObject('key', listKeys(resourceId('Microsoft.CognitiveServices/accounts', parameters('openAiName')), '2023-05-01').key1)))), if(not(empty(parameters('aiSearchName'))), createArray(createObject('name', parameters('aiSearchConnectionName'), 'category', 'CognitiveSearch', 'isSharedToAll', true(), 'target', format('https://{0}.search.windows.net/', parameters('aiSearchName')), 'connectionProperties', createObject('authType', 'ApiKey', 'credentials', createObject('key', if(not(empty(parameters('aiSearchName'))), listAdminKeys(resourceId('Microsoft.Search/searchServices', parameters('aiSearchName')), '2021-04-01-preview').primaryKey, ''))))), 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.30.23.60470", + "templateHash": "14809072872464369520" + }, + "name": "Machine Learning Services Workspaces", + "description": "This module deploys a Machine Learning Services 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. Must be false if `primaryUserAssignedIdentity` is provided." + } + }, + "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 + }, + "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": "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 + }, + "featureStoreSettingType": { + "type": "object", + "properties": { + "computeRuntime": { + "type": "object", + "properties": { + "sparkRuntimeVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The spark runtime version." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Compute runtime config for feature store type workspace." + } + }, + "offlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The offline store connection name." + } + }, + "onlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The online store connection name." + } + } + }, + "nullable": true + }, + "OutboundRuleType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "FQDN": { + "$ref": "#/definitions/FqdnOutboundRuleType" + }, + "PrivateEndpoint": { + "$ref": "#/definitions/PrivateEndpointOutboundRule" + }, + "ServiceTag": { + "$ref": "#/definitions/ServiceTagOutboundRule" + } + } + } + }, + "FqdnOutboundRuleType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "FQDN" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "string", + "metadata": { + "description": "Required. Fully Qualified Domain Name to allow for outbound traffic." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "PrivateEndpointOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "PrivateEndpoint" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound' or 'AllowInternetOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "serviceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target resource for the private endpoint." + } + }, + "sparkEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the private endpoint can be used by jobs running on Spark." + } + }, + "subresourceTarget": { + "type": "string", + "metadata": { + "description": "Required. The sub resource to connect for the private endpoint." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "ServiceTagOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "ServiceTag" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "portRanges": { + "type": "string", + "metadata": { + "description": "Required. The name of the service tag to allow." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. The protocol to allow. Provide an asterisk(*) to allow any protocol." + } + }, + "serviceTag": { + "type": "string", + "metadata": { + "description": "Required. Which ports will be allow traffic by this rule. Provide an asterisk(*) to allow any port." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "managedNetworkSettingType": { + "type": "object", + "properties": { + "isolationMode": { + "type": "string", + "allowedValues": [ + "AllowInternetOutbound", + "AllowOnlyApprovedOutbound", + "Disabled" + ], + "metadata": { + "description": "Required. Isolation mode for the managed network of a machine learning workspace." + } + }, + "outboundRules": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/OutboundRuleType", + "metadata": { + "description": "Required. The outbound rule. The name of the rule is the object key." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Outbound rules for the managed network of a machine learning workspace." + } + } + }, + "nullable": true + }, + "serverlessComputeSettingType": { + "type": "object", + "properties": { + "serverlessComputeCustomSubnet": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of an existing virtual network subnet in which serverless compute nodes should be deployed." + } + }, + "serverlessComputeNoPublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The flag to signal if serverless compute nodes deployed in custom vNet would have no public IP addresses for a workspace with private endpoint." + } + } + }, + "nullable": true + }, + "workspaceHubConfigType": { + "type": "object", + "properties": { + "additionalWorkspaceStorageAccounts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of additional storage accounts to attach to the workspace." + } + }, + "defaultWorkspaceResourceGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default resource group for projects created in the workspace hub." + } + } + }, + "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 + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "connectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + } + }, + "_1.aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/_1.aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/_1.accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/_1.apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/_1.customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/_1.noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/_1.oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/_1.patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/_1.sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the machine learning workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "sku": { + "type": "string", + "allowedValues": [ + "Free", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Required. Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Project", + "Hub", + "FeatureStore" + ], + "metadata": { + "description": "Optional. The type of Azure Machine Learning workspace to create." + } + }, + "associatedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Storage Account. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedKeyVaultResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Key Vault. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedApplicationInsightsResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Application Insights. Required if 'kind' is 'Default' or 'FeatureStore'." + } + }, + "associatedContainerRegistryResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the associated Container Registry." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "hbiWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service." + } + }, + "hubResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the hub to associate with the workspace. Required if 'kind' is set to 'Project'." + } + }, + "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." + } + }, + "computes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Computes to create respectively attach to the workspace." + } + }, + "connections": { + "type": "array", + "items": { + "$ref": "#/definitions/connectionType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Connections to create in the workspace." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." + } + }, + "featureStoreSettings": { + "$ref": "#/definitions/featureStoreSettingType", + "metadata": { + "description": "Conditional. Settings for feature store type workspaces. Required if 'kind' is set to 'FeatureStore'." + } + }, + "managedNetworkSettings": { + "$ref": "#/definitions/managedNetworkSettingType", + "metadata": { + "description": "Optional. Managed Network settings for a machine learning workspace." + } + }, + "serverlessComputeSettings": { + "$ref": "#/definitions/serverlessComputeSettingType", + "metadata": { + "description": "Optional. Settings for serverless compute created in the workspace." + } + }, + "systemDatastoresAuthMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "accessKey", + "identity" + ], + "metadata": { + "description": "Optional. The authentication mode used by the workspace when connecting to the default storage account." + } + }, + "workspaceHubConfig": { + "$ref": "#/definitions/workspaceHubConfigType", + "metadata": { + "description": "Optional. Configuration for workspace hub settings." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this workspace." + } + }, + "discoveryUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. URL for the discovery service to identify regional endpoints for machine learning experimentation services." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "imageBuildCompute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The compute name for image build." + } + }, + "primaryUserAssignedIdentity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The user assigned identity resource ID that represents the workspace identity. Required if 'userAssignedIdentities' is not empty and may not be used if 'systemAssignedIdentity' is enabled." + } + }, + "serviceManagedResourcesSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The service managed resource settings." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of shared private link resources in this workspace. Note: This property is not idempotent." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled." + } + } + }, + "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": { + "AzureML Compute Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e503ece1-11d0-4e8e-8e2c-7a6c3bf38815')]", + "AzureML Data Scientist": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f6c7c914-8db3-469d-8ca1-694a8f32e121')]", + "AzureML Metrics Writer (preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '635dd51f-9968-44d3-b7fb-6d9a6bd613ae')]", + "AzureML Registry User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1823dd4f-9b8c-4ab6-ab4e-7397a3684615')]", + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.machinelearningservices-workspace.{0}.{1}', replace('0.8.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" + } + } + } + } + }, + "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'), '/'))]" + }, + "workspace": { + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2024-04-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]", + "tier": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": "[union(createObject('friendlyName', parameters('name'), 'storageAccount', parameters('associatedStorageAccountResourceId'), 'keyVault', parameters('associatedKeyVaultResourceId'), 'applicationInsights', parameters('associatedApplicationInsightsResourceId'), 'containerRegistry', parameters('associatedContainerRegistryResourceId'), 'hbiWorkspace', parameters('hbiWorkspace'), 'description', parameters('description'), 'discoveryUrl', parameters('discoveryUrl'), 'encryption', if(not(empty(parameters('customerManagedKey'))), createObject('status', 'Enabled', '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('keyVaultArmId', 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'), '/'))), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null()), 'imageBuildCompute', parameters('imageBuildCompute'), 'primaryUserAssignedIdentity', parameters('primaryUserAssignedIdentity'), 'systemDatastoresAuthMode', parameters('systemDatastoresAuthMode'), 'publicNetworkAccess', parameters('publicNetworkAccess'), 'serviceManagedResourcesSettings', parameters('serviceManagedResourcesSettings'), 'featureStoreSettings', parameters('featureStoreSettings'), 'hubResourceId', parameters('hubResourceId'), 'managedNetwork', parameters('managedNetworkSettings'), 'serverlessComputeSettings', parameters('serverlessComputeSettings'), 'workspaceHubConfig', parameters('workspaceHubConfig')), if(not(empty(parameters('sharedPrivateLinkResources'))), createObject('sharedPrivateLinkResources', parameters('sharedPrivateLinkResources')), createObject()))]", + "kind": "[parameters('kind')]", + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "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.MachineLearningServices/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_diagnosticSettings": { + "copy": { + "name": "workspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.MachineLearningServices/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": "[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": [ + "workspace" + ] + }, + "workspace_roleAssignments": { + "copy": { + "name": "workspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.MachineLearningServices/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.MachineLearningServices/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_computes": { + "copy": { + "name": "workspace_computes", + "count": "[length(coalesce(parameters('computes'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-compute', parameters('name'), coalesce(parameters('computes'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].location]" + }, + "sku": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'sku')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'tags')]" + }, + "deployCompute": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'deployCompute')]" + }, + "computeLocation": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'computeLocation')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'description')]" + }, + "disableLocalAuth": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'disableLocalAuth')]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'resourceId')]" + }, + "computeType": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].computeType]" + }, + "properties": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'properties')]" + } + }, + "template": { + "$schema": "https://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": "6461308246344228681" + }, + "name": "Machine Learning Services Workspaces Computes", + "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", + "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": { + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 16, + "metadata": { + "description": "Required. Name of the compute." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Specifies the location of the resource." + } + }, + "sku": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Basic", + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Specifies the sku, also referred as \"edition\". Required for creating a compute resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Contains resource tags defined as key-value pairs. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "deployCompute": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to specify whether to deploy the compute. Required only for attach (i.e. providing a resource ID), as in this case the operation is not idempotent, i.e. a second deployment will fail. Therefore, this flag needs to be set to \"false\" as long as the compute resource exists." + } + }, + "computeLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for the underlying compute. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the Machine Learning compute." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure customers can use only MSI and AAD exclusively for authentication." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ARM resource ID of the underlying compute." + } + }, + "computeType": { + "type": "string", + "allowedValues": [ + "AKS", + "AmlCompute", + "ComputeInstance", + "Databricks", + "DataFactory", + "DataLakeAnalytics", + "HDInsight", + "Kubernetes", + "SynapseSpark", + "VirtualMachine" + ], + "metadata": { + "description": "Required. Set the object type." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the compute. Will be ignored in case \"resourceId\" is set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + } + }, + "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())]" + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "compute": { + "condition": "[equals(parameters('deployCompute'), true())]", + "type": "Microsoft.MachineLearningServices/workspaces/computes", + "apiVersion": "2022-10-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[if(empty(parameters('resourceId')), parameters('tags'), null())]", + "sku": "[if(empty(parameters('resourceId')), createObject('name', parameters('sku'), 'tier', parameters('sku')), null())]", + "identity": "[if(empty(parameters('resourceId')), variables('identity'), null())]", + "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the compute." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the compute." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the compute was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('compute', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('compute', '2022-10-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "workspace", + "workspace_privateEndpoints" + ] + }, + "workspace_connections": { + "copy": { + "name": "workspace_connections", + "count": "[length(parameters('connections'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-connection', parameters('name'), parameters('connections')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('connections')[copyIndex()].name]" + }, + "category": { + "value": "[parameters('connections')[copyIndex()].category]" + }, + "expiryTime": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'expiryTime')]" + }, + "isSharedToAll": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'isSharedToAll')]" + }, + "metadata": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'metadata')]" + }, + "sharedUserList": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'sharedUserList')]" + }, + "target": { + "value": "[parameters('connections')[copyIndex()].target]" + }, + "value": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'value')]" + }, + "connectionProperties": { + "value": "[parameters('connections')[copyIndex()].connectionProperties]" + } + }, + "template": { + "$schema": "https://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": "11897886685116125832" + }, + "name": "Machine Learning Services Workspaces Connections", + "description": "This module creates a connection in a Machine Learning Services workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "metadataType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_export!": true + } + }, + "aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "accountKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccountKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccountKey", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + } + }, + "workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + } + }, + "workspaceConnectionAccountKey": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection key." + } + } + } + }, + "workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + } + }, + "workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + } + }, + "workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + } + }, + "workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + } + }, + "workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + } + }, + "workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + } + }, + "workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "$ref": "#/definitions/metadataType", + "defaultValue": {}, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "connection": { + "type": "Microsoft.MachineLearningServices/workspaces/connections", + "apiVersion": "2024-04-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "properties": "[union(createObject('category', parameters('category'), 'expiryTime', parameters('expiryTime'), 'isSharedToAll', parameters('isSharedToAll'), 'metadata', parameters('metadata'), 'sharedUserList', parameters('sharedUserList'), 'target', parameters('target'), 'value', parameters('value')), parameters('connectionProperties'))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the connection." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/connections', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the connection." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the connection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), 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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')))))), 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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')), '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": "3308873178893851812" + }, + "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.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" + } + } + } + } + }, + "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]" + }, + "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 machine learning service." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the machine learning service was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the machine learning service." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('workspace', '2024-04-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('workspace', '2024-04-01-preview', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "value": "hub-workspace" + }, + "resourceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'hub-workspace'), '2022-09-01').outputs.resourceId.value]" + }, + "principalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'hub-workspace'), '2022-09-01').outputs.systemAssignedMIPrincipalId.value]" + } + } + } + }, + "dependsOn": [ + "hubDependencies" + ] + }, + "project": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-project', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "hubResourceId": { + "value": "[reference('hub').outputs.resourceId.value]" + }, + "keyVaultName": { + "value": "[reference('hubDependencies').outputs.keyVaultName.value]" + }, + "userAssignedName": { + "value": "[parameters('userAssignedtName')]" + }, + "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": "11662488567540742511" + }, + "name": "Azd Machine Learning workspace", + "description": "Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "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. Must be false if `primaryUserAssignedIdentity` is provided." + } + }, + "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 machine learning workspace." + } + }, + "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." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + }, + "projectSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Free", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace." + } + }, + "projectKind": { + "type": "string", + "defaultValue": "Project", + "allowedValues": [ + "Default", + "Project", + "Hub", + "FeatureStore" + ], + "metadata": { + "description": "Optional. The type of Azure Machine Learning workspace to create." + } + }, + "hbiWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled." + } + }, + "hubResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the AI Studio Hub Resource where this project should be created." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the key vault." + } + }, + "projectManagedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for the machine learning resource. At least one identity type is required." + } + }, + "userAssignedName": { + "type": "string", + "metadata": { + "description": "Required. The name of the user assigned identity." + } + }, + "roleDefinitionIdOrName": { + "type": "array", + "defaultValue": [ + "f6c7c914-8db3-469d-8ca1-694a8f32e121", + "ea01e6af-a1c1-4350-9563-ad00f8c72ec5" + ], + "metadata": { + "description": "Optional. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-mlproject.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "project": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-project', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "sku": { + "value": "[parameters('projectSku')]" + }, + "kind": { + "value": "[parameters('projectKind')]" + }, + "managedIdentities": { + "value": "[parameters('projectManagedIdentities')]" + }, + "hbiWorkspace": { + "value": "[parameters('hbiWorkspace')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "hubResourceId": { + "value": "[parameters('hubResourceId')]" + }, + "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.29.47.4906", + "templateHash": "8914196510655371542" + }, + "name": "Machine Learning Services Workspaces", + "description": "This module deploys a Machine Learning Services 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. Must be false if `primaryUserAssignedIdentity` is provided." + } + }, + "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 + }, + "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": "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 + }, + "featureStoreSettingType": { + "type": "object", + "properties": { + "computeRuntime": { + "type": "object", + "properties": { + "sparkRuntimeVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The spark runtime version." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Compute runtime config for feature store type workspace." + } + }, + "offlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The offline store connection name." + } + }, + "onlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The online store connection name." + } + } + }, + "nullable": true + }, + "OutboundRuleType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "FQDN": { + "$ref": "#/definitions/FqdnOutboundRuleType" + }, + "PrivateEndpoint": { + "$ref": "#/definitions/PrivateEndpointOutboundRule" + }, + "ServiceTag": { + "$ref": "#/definitions/ServiceTagOutboundRule" + } + } + } + }, + "FqdnOutboundRuleType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "FQDN" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "string", + "metadata": { + "description": "Required. Fully Qualified Domain Name to allow for outbound traffic." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "PrivateEndpointOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "PrivateEndpoint" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound' or 'AllowInternetOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "serviceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target resource for the private endpoint." + } + }, + "sparkEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the private endpoint can be used by jobs running on Spark." + } + }, + "subresourceTarget": { + "type": "string", + "metadata": { + "description": "Required. The sub resource to connect for the private endpoint." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "ServiceTagOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "ServiceTag" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "portRanges": { + "type": "string", + "metadata": { + "description": "Required. The name of the service tag to allow." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. The protocol to allow. Provide an asterisk(*) to allow any protocol." + } + }, + "serviceTag": { + "type": "string", + "metadata": { + "description": "Required. Which ports will be allow traffic by this rule. Provide an asterisk(*) to allow any port." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "managedNetworkSettingType": { + "type": "object", + "properties": { + "isolationMode": { + "type": "string", + "allowedValues": [ + "AllowInternetOutbound", + "AllowOnlyApprovedOutbound", + "Disabled" + ], + "metadata": { + "description": "Required. Isolation mode for the managed network of a machine learning workspace." + } + }, + "outboundRules": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/OutboundRuleType", + "metadata": { + "description": "Required. The outbound rule. The name of the rule is the object key." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Outbound rules for the managed network of a machine learning workspace." + } + } + }, + "nullable": true + }, + "serverlessComputeSettingType": { + "type": "object", + "properties": { + "serverlessComputeCustomSubnet": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of an existing virtual network subnet in which serverless compute nodes should be deployed." + } + }, + "serverlessComputeNoPublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The flag to signal if serverless compute nodes deployed in custom vNet would have no public IP addresses for a workspace with private endpoint." + } + } + }, + "nullable": true + }, + "workspaceHubConfigType": { + "type": "object", + "properties": { + "additionalWorkspaceStorageAccounts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of additional storage accounts to attach to the workspace." + } + }, + "defaultWorkspaceResourceGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default resource group for projects created in the workspace hub." + } + } + }, + "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 + }, + "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. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "connectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + } + }, + "_1.aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/_1.aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/_1.accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/_1.apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/_1.customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/_1.noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/_1.oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/_1.patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/_1.sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the machine learning workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "sku": { + "type": "string", + "allowedValues": [ + "Free", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Required. Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Project", + "Hub", + "FeatureStore" + ], + "metadata": { + "description": "Optional. The type of Azure Machine Learning workspace to create." + } + }, + "associatedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Storage Account. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedKeyVaultResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Key Vault. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedApplicationInsightsResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Application Insights. Required if 'kind' is 'Default' or 'FeatureStore'." + } + }, + "associatedContainerRegistryResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the associated Container Registry." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "hbiWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service." + } + }, + "hubResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the hub to associate with the workspace. Required if 'kind' is set to 'Project'." + } + }, + "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." + } + }, + "computes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Computes to create respectively attach to the workspace." + } + }, + "connections": { + "type": "array", + "items": { + "$ref": "#/definitions/connectionType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Connections to create in the workspace." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." + } + }, + "featureStoreSettings": { + "$ref": "#/definitions/featureStoreSettingType", + "metadata": { + "description": "Conditional. Settings for feature store type workspaces. Required if 'kind' is set to 'FeatureStore'." + } + }, + "managedNetworkSettings": { + "$ref": "#/definitions/managedNetworkSettingType", + "metadata": { + "description": "Optional. Managed Network settings for a machine learning workspace." + } + }, + "serverlessComputeSettings": { + "$ref": "#/definitions/serverlessComputeSettingType", + "metadata": { + "description": "Optional. Settings for serverless compute created in the workspace." + } + }, + "systemDatastoresAuthMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "accessKey", + "identity" + ], + "metadata": { + "description": "Optional. The authentication mode used by the workspace when connecting to the default storage account." + } + }, + "workspaceHubConfig": { + "$ref": "#/definitions/workspaceHubConfigType", + "metadata": { + "description": "Optional. Configuration for workspace hub settings." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this workspace." + } + }, + "discoveryUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. URL for the discovery service to identify regional endpoints for machine learning experimentation services." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "imageBuildCompute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The compute name for image build." + } + }, + "primaryUserAssignedIdentity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The user assigned identity resource ID that represents the workspace identity. Required if 'userAssignedIdentities' is not empty and may not be used if 'systemAssignedIdentity' is enabled." + } + }, + "serviceManagedResourcesSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The service managed resource settings." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of shared private link resources in this workspace. Note: This property is not idempotent." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled." + } + } + }, + "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": { + "AzureML Compute Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e503ece1-11d0-4e8e-8e2c-7a6c3bf38815')]", + "AzureML Data Scientist": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f6c7c914-8db3-469d-8ca1-694a8f32e121')]", + "AzureML Metrics Writer (preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '635dd51f-9968-44d3-b7fb-6d9a6bd613ae')]", + "AzureML Registry User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1823dd4f-9b8c-4ab6-ab4e-7397a3684615')]", + "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')]" + } + }, + "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'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.machinelearningservices-workspace.{0}.{1}', replace('0.7.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" + } + } + } + } + }, + "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'), '/'))]" + }, + "workspace": { + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2024-04-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]", + "tier": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": "[union(createObject('friendlyName', parameters('name'), 'storageAccount', parameters('associatedStorageAccountResourceId'), 'keyVault', parameters('associatedKeyVaultResourceId'), 'applicationInsights', parameters('associatedApplicationInsightsResourceId'), 'containerRegistry', parameters('associatedContainerRegistryResourceId'), 'hbiWorkspace', parameters('hbiWorkspace'), 'description', parameters('description'), 'discoveryUrl', parameters('discoveryUrl'), 'encryption', if(not(empty(parameters('customerManagedKey'))), createObject('status', 'Enabled', '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('keyVaultArmId', 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'), '/'))), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null()), 'imageBuildCompute', parameters('imageBuildCompute'), 'primaryUserAssignedIdentity', parameters('primaryUserAssignedIdentity'), 'systemDatastoresAuthMode', parameters('systemDatastoresAuthMode'), 'publicNetworkAccess', parameters('publicNetworkAccess'), 'serviceManagedResourcesSettings', parameters('serviceManagedResourcesSettings'), 'featureStoreSettings', parameters('featureStoreSettings'), 'hubResourceId', parameters('hubResourceId'), 'managedNetwork', parameters('managedNetworkSettings'), 'serverlessComputeSettings', parameters('serverlessComputeSettings'), 'workspaceHubConfig', parameters('workspaceHubConfig')), if(not(empty(parameters('sharedPrivateLinkResources'))), createObject('sharedPrivateLinkResources', parameters('sharedPrivateLinkResources')), createObject()))]", + "kind": "[parameters('kind')]", + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "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.MachineLearningServices/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_diagnosticSettings": { + "copy": { + "name": "workspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.MachineLearningServices/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": "[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": [ + "workspace" + ] + }, + "workspace_roleAssignments": { + "copy": { + "name": "workspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.MachineLearningServices/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.MachineLearningServices/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_computes": { + "copy": { + "name": "workspace_computes", + "count": "[length(coalesce(parameters('computes'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-compute', parameters('name'), coalesce(parameters('computes'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].location]" + }, + "sku": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'sku')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'tags')]" + }, + "deployCompute": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'deployCompute')]" + }, + "computeLocation": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'computeLocation')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'description')]" + }, + "disableLocalAuth": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'disableLocalAuth')]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'resourceId')]" + }, + "computeType": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].computeType]" + }, + "properties": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'properties')]" + } + }, + "template": { + "$schema": "https://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": "8580750401363518569" + }, + "name": "Machine Learning Services Workspaces Computes", + "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", + "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": { + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 16, + "metadata": { + "description": "Required. Name of the compute." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Specifies the location of the resource." + } + }, + "sku": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Basic", + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Specifies the sku, also referred as \"edition\". Required for creating a compute resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Contains resource tags defined as key-value pairs. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "deployCompute": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to specify whether to deploy the compute. Required only for attach (i.e. providing a resource ID), as in this case the operation is not idempotent, i.e. a second deployment will fail. Therefore, this flag needs to be set to \"false\" as long as the compute resource exists." + } + }, + "computeLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for the underlying compute. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the Machine Learning compute." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure customers can use only MSI and AAD exclusively for authentication." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ARM resource ID of the underlying compute." + } + }, + "computeType": { + "type": "string", + "allowedValues": [ + "AKS", + "AmlCompute", + "ComputeInstance", + "Databricks", + "DataFactory", + "DataLakeAnalytics", + "HDInsight", + "Kubernetes", + "SynapseSpark", + "VirtualMachine" + ], + "metadata": { + "description": "Required. Set the object type." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the compute. Will be ignored in case \"resourceId\" is set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + } + }, + "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())]" + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "compute": { + "condition": "[equals(parameters('deployCompute'), true())]", + "type": "Microsoft.MachineLearningServices/workspaces/computes", + "apiVersion": "2022-10-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[if(empty(parameters('resourceId')), parameters('tags'), null())]", + "sku": "[if(empty(parameters('resourceId')), createObject('name', parameters('sku'), 'tier', parameters('sku')), null())]", + "identity": "[if(empty(parameters('resourceId')), variables('identity'), null())]", + "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the compute." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the compute." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the compute was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('compute', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('compute', '2022-10-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "workspace", + "workspace_privateEndpoints" + ] + }, + "workspace_connections": { + "copy": { + "name": "workspace_connections", + "count": "[length(parameters('connections'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-connection', parameters('name'), parameters('connections')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('connections')[copyIndex()].name]" + }, + "category": { + "value": "[parameters('connections')[copyIndex()].category]" + }, + "expiryTime": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'expiryTime')]" + }, + "isSharedToAll": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'isSharedToAll')]" + }, + "metadata": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'metadata')]" + }, + "sharedUserList": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'sharedUserList')]" + }, + "target": { + "value": "[parameters('connections')[copyIndex()].target]" + }, + "value": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'value')]" + }, + "connectionProperties": { + "value": "[parameters('connections')[copyIndex()].connectionProperties]" + } + }, + "template": { + "$schema": "https://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": "2277907099827503661" + }, + "name": "Machine Learning Services Workspaces Connections", + "description": "This module creates a connection in a Machine Learning Services workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "metadataType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_export!": true + } + }, + "aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "accountKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccountKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccountKey", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + } + }, + "workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + } + }, + "workspaceConnectionAccountKey": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection key." + } + } + } + }, + "workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + } + }, + "workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + } + }, + "workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + } + }, + "workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + } + }, + "workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + } + }, + "workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + } + }, + "workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "$ref": "#/definitions/metadataType", + "defaultValue": {}, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "connection": { + "type": "Microsoft.MachineLearningServices/workspaces/connections", + "apiVersion": "2024-04-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "properties": "[union(createObject('category', parameters('category'), 'expiryTime', parameters('expiryTime'), 'isSharedToAll', parameters('isSharedToAll'), 'metadata', parameters('metadata'), 'sharedUserList', parameters('sharedUserList'), 'target', parameters('target'), 'value', parameters('value')), parameters('connectionProperties'))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the connection." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/connections', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the connection." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the connection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), 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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')))))), 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.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')), '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": "3308873178893851812" + }, + "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.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" + } + } + } + } + }, + "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]" + }, + "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 machine learning service." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the machine learning service was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the machine learning service." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('workspace', '2024-04-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('workspace', '2024-04-01-preview', 'full').location]" + } + } + } + } + }, + "keyVaultAccess": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "accessPolicies": { + "value": [ + { + "objectId": "[reference('project').outputs.systemAssignedMIPrincipalId.value]", + "permissions": { + "secrets": [ + "get", + "list" + ] + } + } + ] + }, + "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.29.47.4906", + "templateHash": "10085839006881327962" + }, + "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": { + "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": "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": "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('0.9.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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "7494731697751039419" + }, + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "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.29.47.4906", + "templateHash": "114626909766354577" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "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 + } + }, + "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": { + "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')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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'))]" + }, + "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.29.47.4906", + "templateHash": "14269695922191217406" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "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 + } + }, + "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": { + "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": { + "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())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "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": { + "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], '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": [ + "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", + "metadata": { + "description": "The private endpoints of the key vault." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(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": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } + } + }, + "dependsOn": [ + "keyVault", + "project" + ] + }, + "mlServiceRoleAssigned": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-roleassignment', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('userAssignedName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "roleAssignments": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('roleDefinitionIdOrName'))]", + "input": "[createObject('principalId', reference('project').outputs.systemAssignedMIPrincipalId.value, 'roleDefinitionIdOrName', parameters('roleDefinitionIdOrName')[copyIndex('value')], 'principalType', 'ServicePrincipal')]" + } + ] + }, + "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.29.47.4906", + "templateHash": "10609859695208799167" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity.", + "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 + }, + "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('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" + } + } + } + } + }, + "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.29.47.4906", + "templateHash": "3716898257490923786" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential.", + "owner": "Azure/module-maintainers" + }, + "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]" + } + } + } + }, + "dependsOn": [ + "project" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the machine learning workspace were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "projectResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the machine learning workspace." + }, + "value": "[reference('project').outputs.resourceId.value]" + }, + "projectName": { + "type": "string", + "metadata": { + "description": "The resource name of the machine learning workspace." + }, + "value": "[reference('project').outputs.name.value]" + }, + "projectPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the machine learning workspace." + }, + "value": "[reference('project').outputs.systemAssignedMIPrincipalId.value]" + } + } + } + }, + "dependsOn": [ + "hub", + "hubDependencies" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the module was deployed to." + }, + "value": "[resourceGroup().name]" + }, + "hubName": { + "type": "string", + "metadata": { + "description": "The name of the ai studio hub." + }, + "value": "[reference('hub').outputs.name.value]" + }, + "hubPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the ai studio hub." + }, + "value": "[reference('hub').outputs.principalId.value]" + }, + "projectName": { + "type": "string", + "metadata": { + "description": "The name of the ai studio project." + }, + "value": "[reference('project').outputs.projectName.value]" + }, + "projectPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the ai studio project." + }, + "value": "[reference('project').outputs.projectPrincipalId.value]" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[reference('hubDependencies').outputs.keyVaultName.value]" + }, + "keyVaultEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the key vault." + }, + "value": "[reference('hubDependencies').outputs.keyVaultEndpoint.value]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('hubDependencies').outputs.applicationInsightsName.value]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the log analytics workspace." + }, + "value": "[reference('hubDependencies').outputs.logAnalyticsWorkspaceName.value]" + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[reference('hubDependencies').outputs.containerRegistryName.value]" + }, + "containerRegistryEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the container registry." + }, + "value": "[reference('hubDependencies').outputs.containerRegistryEndpoint.value]" + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "The name of the storage account." + }, + "value": "[reference('hubDependencies').outputs.storageAccountName.value]" + }, + "openAiName": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services." + }, + "value": "[reference('hubDependencies').outputs.cognitiveServicesName.value]" + }, + "openAiEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the cognitive services." + }, + "value": "[reference('hubDependencies').outputs.cognitiveServicesEndpoint.value]" + }, + "searchServiceName": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[reference('hubDependencies').outputs.searchServiceName.value]" + }, + "searchServiceEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[reference('hubDependencies').outputs.searchServiceEndpoint.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/ml-ai-environment/modules/hub.bicep b/avm/ptn/azd/ml-ai-environment/modules/hub.bicep new file mode 100644 index 0000000000..1eeade3a0a --- /dev/null +++ b/avm/ptn/azd/ml-ai-environment/modules/hub.bicep @@ -0,0 +1,132 @@ +@description('Required. The AI Studio Hub Resource name.') +param name string + +@description('Required. The storage account ID to use for the AI Studio Hub Resource.') +param storageAccountResourceId string + +@description('Required. The key vault ID to use for the AI Studio Hub Resource.') +param keyVaultResourceId string + +@description('Optional. The application insights ID to use for the AI Studio Hub Resource.') +param applicationInsightsResourceId string = '' + +@description('Optional. The container registry ID to use for the AI Studio Hub Resource.') +param containerRegistryResourceId string = '' + +@description('Required. The OpenAI Cognitive Services account name to use for the AI Studio Hub Resource.') +param openAiName string + +@description('Optional. The Azure Cognitive Search service name to use for the AI Studio Hub Resource.') +param aiSearchName string = '' + +@description('Required. The Azure Cognitive Search service connection name to use for the AI Studio Hub Resource.') +param aiSearchConnectionName string + +@description('Required. The OpenAI Content Safety connection name to use for the AI Studio Hub Resource.') +param openAiContentSafetyConnectionName string + +@description('Optional. The SKU name to use for the AI Studio Hub Resource.') +@allowed(['Basic', 'Free', 'Premium', 'Standard']) +param skuName string = 'Basic' + +@description('Optional. The public network access setting to use for the AI Studio Hub Resource.') +@allowed(['Enabled', 'Disabled']) +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object = {} + +var aiSearchConnection = !empty(aiSearchName) ? [{ + name: aiSearchConnectionName + category: 'CognitiveSearch' + isSharedToAll: true + target: 'https://${search.name}.search.windows.net/' + connectionProperties: { + authType: 'ApiKey' + credentials: { + key: !empty(aiSearchName) ? search.listAdminKeys().primaryKey : '' + } + } +}] : [] + +var connections = [ + { + name: 'aoai-connection' + category: 'AzureOpenAI' + isSharedToAll: true + metadata: { + ApiVersion: '2024-02-01' + ApiType: 'azure' + ResourceId: openAi.id + } + target: openAi.properties.endpoints['OpenAI Language Model Instance API'] + connectionProperties: { + authType: 'ApiKey' + credentials: { + key: openAi.listKeys().key1 + } + } + } + { + name: openAiContentSafetyConnectionName + category: 'AzureOpenAI' + isSharedToAll: true + target: openAi.properties.endpoints['Content Safety'] + metadata: { + ApiVersion: '2023-07-01-preview' + ApiType: 'azure' + ResourceId: openAi.id + } + connectionProperties: { + authType: 'ApiKey' + credentials: { + key: openAi.listKeys().key1 + } + } + } +] + +// ================ // +// Resources // +// ================ // + +resource openAi 'Microsoft.CognitiveServices/accounts@2023-05-01' existing = { + name: openAiName +} + +resource search 'Microsoft.Search/searchServices@2021-04-01-preview' existing = if (!empty(aiSearchName)) { + name: aiSearchName +} + +module hub 'br/public:avm/res/machine-learning-services/workspace:0.8.1' = { + name: 'hub-workspace' + params: { + name: name + sku: skuName + location: location + tags: tags + kind: 'Hub' + associatedKeyVaultResourceId: keyVaultResourceId + associatedStorageAccountResourceId: storageAccountResourceId + associatedApplicationInsightsResourceId: !empty(applicationInsightsResourceId) ? applicationInsightsResourceId : null + associatedContainerRegistryResourceId: !empty(containerRegistryResourceId) ? containerRegistryResourceId : null + hbiWorkspace: false + managedNetworkSettings: { + isolationMode: 'Disabled' + } + publicNetworkAccess: publicNetworkAccess + discoveryUrl: 'https://${location}.api.azureml.ms/discovery' + connections: union(connections, aiSearchConnection) + } +} + +// ================ // +// Outputs // +// ================ // + +output name string = hub.name +output resourceId string = hub.outputs.resourceId +output principalId string = hub.outputs.systemAssignedMIPrincipalId diff --git a/avm/ptn/azd/ml-ai-environment/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/ml-ai-environment/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..ec8f688f21 --- /dev/null +++ b/avm/ptn/azd/ml-ai-environment/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}-azd-ml-ai-environment-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'maemin' + +@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 + keyVaultName: '${namePrefix}${serviceShort}kv00' + storageAccountName: '${namePrefix}${serviceShort}sa001' + hubName: '${namePrefix}${serviceShort}hub001' + projectName: '${namePrefix}${serviceShort}pro001' + userAssignedtName: '${namePrefix}${serviceShort}ua001' + cognitiveServicesName: '${namePrefix}${serviceShort}cs001' + openAiConnectionName: '${namePrefix}${serviceShort}ai001-connection' + searchConnectionName: '${namePrefix}${serviceShort}search001-connection' + } + } +] diff --git a/avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep b/avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..13556d5d28 --- /dev/null +++ b/avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module using large parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-ml-ai-environment-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'maemax' + +@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: { + location: resourceLocation + hubName: '${namePrefix}${serviceShort}hub001' + keyVaultName: '${namePrefix}${serviceShort}kv001' + cognitiveServicesName: '${namePrefix}${serviceShort}cs001' + projectName: '${namePrefix}${serviceShort}pro001' + storageAccountName: '${namePrefix}${serviceShort}sta001' + userAssignedtName: '${namePrefix}${serviceShort}ua001' + containerRegistryName: '${namePrefix}${serviceShort}cr001' + applicationInsightsName: '${namePrefix}${serviceShort}appin001' + logAnalyticsName: '${namePrefix}${serviceShort}la001' + searchServiceName: '${namePrefix}${serviceShort}search001' + openAiConnectionName: '${namePrefix}${serviceShort}ai001-connection' + searchConnectionName: '${namePrefix}${serviceShort}search001-connection' + cognitiveServicesDeployments: [ + { + name: 'gpt-35-turbo' + model: { + name: 'gpt-35-turbo' + format: 'OpenAI' + version: '0613' + } + sku: { + name: 'Standard' + capacity: 20 + } + } + ] + } + } +] diff --git a/avm/ptn/azd/ml-ai-environment/version.json b/avm/ptn/azd/ml-ai-environment/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/ml-ai-environment/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From b420117251686a78e688ed1bf10ed849f6837f20 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 14 Oct 2024 12:13:30 +0200 Subject: [PATCH 77/93] fix: Aligned AKS interface to AVM specs & added UDT (#3506) ## Description - Aligned AKS interface to AVM specs - Added UDT & mapping for primary agent pool Depending on #3228 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.container-service.managed-cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml/badge.svg?branch=users%2Falsehr%2FcontainerServiceInterfaceFix&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- .../managed-cluster/README.md | 577 ++++++++++--- .../managed-cluster/agent-pool/README.md | 22 +- .../managed-cluster/agent-pool/main.bicep | 18 +- .../managed-cluster/agent-pool/main.json | 29 +- .../managed-cluster/main.bicep | 140 +++- .../managed-cluster/main.json | 776 +++++++++--------- .../maintenance-configurations/main.json | 4 +- .../tests/e2e/automatic/main.test.bicep | 3 +- .../tests/e2e/azure/main.test.bicep | 16 +- .../tests/e2e/defaults/main.test.bicep | 2 +- .../tests/e2e/kubenet/main.test.bicep | 8 +- .../tests/e2e/priv/main.test.bicep | 12 +- .../tests/e2e/waf-aligned/main.test.bicep | 14 +- 13 files changed, 1045 insertions(+), 576 deletions(-) diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md index b5cbcf20e7..27d80860c1 100644 --- a/avm/res/container-service/managed-cluster/README.md +++ b/avm/res/container-service/managed-cluster/README.md @@ -54,7 +54,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' // Required parameters param name = 'csauto001' -param primaryAgentPoolProfile = [ +param primaryAgentPoolProfiles = [ { count: 3 mode: 'System' @@ -217,10 +217,10 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + vnetSubnetResourceId: '' } ] // Non-required parameters agentPools: [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -261,11 +261,11 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + vnetSubnetResourceId: '' } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -282,7 +282,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + vnetSubnetResourceId: '' } ] autoNodeOsUpgradeProfileUpgradeChannel: 'Unmanaged' @@ -422,7 +422,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' ] } - monitoringWorkspaceId: '' + monitoringWorkspaceResourceId: '' networkDataplane: 'azure' networkPlugin: 'azure' networkPluginMode: 'overlay' @@ -472,11 +472,11 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "vnetSubnetResourceId": "" } ] }, @@ -501,7 +501,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "vnetSubnetResourceId": "" }, { "availabilityZones": [ - "3" + 3 ], "count": 2, "enableAutoScaling": true, @@ -540,7 +540,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "vnetSubnetResourceId": "" } ] }, @@ -723,8 +723,8 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "monitoringWorkspaceResourceId": { + "value": "" }, "networkDataplane": { "value": "azure" @@ -785,10 +785,10 @@ using 'br/public:avm/res/container-service/managed-cluster:' // Required parameters param name = 'csmaz001' -param primaryAgentPoolProfile = [ +param primaryAgentPoolProfiles = [ { availabilityZones: [ - '3' + 3 ] count: 1 enableAutoScaling: true @@ -804,14 +804,14 @@ param primaryAgentPoolProfile = [ osType: 'Linux' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '' + vnetSubnetResourceId: '' } ] // Non-required parameters param agentPools = [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -829,11 +829,11 @@ param agentPools = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '' + vnetSubnetResourceId: '' } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -850,7 +850,7 @@ param agentPools = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '' + vnetSubnetResourceId: '' } ] param autoNodeOsUpgradeProfileUpgradeChannel = 'Unmanaged' @@ -990,7 +990,7 @@ param managedIdentities = { '' ] } -param monitoringWorkspaceId = '' +param monitoringWorkspaceResourceId = '' param networkDataplane = 'azure' param networkPlugin = 'azure' param networkPluginMode = 'overlay' @@ -1040,7 +1040,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' // Required parameters param name = 'csmin001' -param primaryAgentPoolProfile = [ +param primaryAgentPoolProfiles = [ { count: 3 mode: 'System' @@ -1141,10 +1141,10 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' // Required parameters param name = 'csmkube001' -param primaryAgentPoolProfile = [ +param primaryAgentPoolProfiles = [ { availabilityZones: [ - '3' + 3 ] count: 1 enableAutoScaling: true @@ -1436,7 +1436,7 @@ param primaryAgentPoolProfile = [ param agentPools = [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -1456,7 +1456,7 @@ param agentPools = [ } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -1540,10 +1540,10 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + vnetSubnetResourceId: '' } ] // Non-required parameters agentPools: [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -1583,11 +1583,11 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + vnetSubnetResourceId: '' } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -1638,11 +1638,11 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "vnetSubnetResourceId": "" } ] }, @@ -1667,7 +1667,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "vnetSubnetResourceId": "" }, { "availabilityZones": [ - "3" + 3 ], "count": 2, "enableAutoScaling": true, @@ -1752,10 +1752,10 @@ using 'br/public:avm/res/container-service/managed-cluster:' // Required parameters param name = 'csmpriv001' -param primaryAgentPoolProfile = [ +param primaryAgentPoolProfiles = [ { availabilityZones: [ - '3' + 3 ] count: 1 enableAutoScaling: true @@ -1771,14 +1771,14 @@ param primaryAgentPoolProfile = [ osType: 'Linux' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '' + vnetSubnetResourceId: '' } ] // Non-required parameters param agentPools = [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -1795,11 +1795,11 @@ param agentPools = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '' + vnetSubnetResourceId: '' } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -1850,10 +1850,10 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + vnetSubnetResourceId: '' } ] // Non-required parameters agentPools: [ { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -1894,11 +1894,11 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' + vnetSubnetResourceId: '' } { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -1990,7 +1990,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:' ] } - monitoringWorkspaceId: '' + monitoringWorkspaceResourceId: '' networkPlugin: 'azure' networkPolicy: 'azure' omsAgentEnabled: true @@ -2022,11 +2022,11 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "vnetSubnetResourceId": "" } ] }, @@ -2051,7 +2051,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "vnetSubnetResourceId": "" }, { "availabilityZones": [ - "3" + 3 ], "count": 3, "enableAutoScaling": true, @@ -2186,8 +2186,8 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:" + "monitoringWorkspaceResourceId": { + "value": "" }, "networkPlugin": { "value": "azure" @@ -2230,10 +2230,10 @@ using 'br/public:avm/res/container-service/managed-cluster:' // Required parameters param name = 'cswaf001' -param primaryAgentPoolProfile = [ +param primaryAgentPoolProfiles = [ { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -2249,14 +2249,14 @@ param primaryAgentPoolProfile = [ osType: 'Linux' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '' + vnetSubnetResourceId: '' } ] // Non-required parameters param agentPools = [ { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -2274,11 +2274,11 @@ param agentPools = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '' + vnetSubnetResourceId: '' } { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -2370,7 +2370,7 @@ param managedIdentities = { '' ] } -param monitoringWorkspaceId = '' +param monitoringWorkspaceResourceId = '' param networkPlugin = 'azure' param networkPolicy = 'azure' param omsAgentEnabled = true @@ -2394,7 +2394,7 @@ param tags = { | Parameter | Type | Description | | :-- | :-- | :-- | | [`name`](#parameter-name) | string | Specifies the name of the AKS cluster. | -| [`primaryAgentPoolProfile`](#parameter-primaryagentpoolprofile) | array | Properties of the primary agent pool. | +| [`primaryAgentPoolProfiles`](#parameter-primaryagentpoolprofiles) | array | Properties of the primary agent pool. | **Conditional parameters** @@ -2421,12 +2421,12 @@ param tags = { | [`autoNodeOsUpgradeProfileUpgradeChannel`](#parameter-autonodeosupgradeprofileupgradechannel) | string | Auto-upgrade channel on the Node Os. | | [`autoScalerProfileBalanceSimilarNodeGroups`](#parameter-autoscalerprofilebalancesimilarnodegroups) | bool | Specifies the balance of similar node groups for the auto-scaler of the AKS cluster. | | [`autoScalerProfileExpander`](#parameter-autoscalerprofileexpander) | string | Specifies the expand strategy for the auto-scaler of the AKS cluster. | -| [`autoScalerProfileMaxEmptyBulkDelete`](#parameter-autoscalerprofilemaxemptybulkdelete) | string | Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster. | -| [`autoScalerProfileMaxGracefulTerminationSec`](#parameter-autoscalerprofilemaxgracefulterminationsec) | string | Specifies the max graceful termination time interval in seconds for the auto-scaler of the AKS cluster. | +| [`autoScalerProfileMaxEmptyBulkDelete`](#parameter-autoscalerprofilemaxemptybulkdelete) | int | Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster. | +| [`autoScalerProfileMaxGracefulTerminationSec`](#parameter-autoscalerprofilemaxgracefulterminationsec) | int | Specifies the max graceful termination time interval in seconds for the auto-scaler of the AKS cluster. | | [`autoScalerProfileMaxNodeProvisionTime`](#parameter-autoscalerprofilemaxnodeprovisiontime) | string | Specifies the maximum node provisioning time for the auto-scaler of the AKS cluster. Values must be an integer followed by an "m". No unit of time other than minutes (m) is supported. | -| [`autoScalerProfileMaxTotalUnreadyPercentage`](#parameter-autoscalerprofilemaxtotalunreadypercentage) | string | Specifies the mximum total unready percentage for the auto-scaler of the AKS cluster. The maximum is 100 and the minimum is 0. | +| [`autoScalerProfileMaxTotalUnreadyPercentage`](#parameter-autoscalerprofilemaxtotalunreadypercentage) | int | Specifies the mximum total unready percentage for the auto-scaler of the AKS cluster. The maximum is 100 and the minimum is 0. | | [`autoScalerProfileNewPodScaleUpDelay`](#parameter-autoscalerprofilenewpodscaleupdelay) | string | For scenarios like burst/batch scale where you do not want CA to act before the kubernetes scheduler could schedule all the pods, you can tell CA to ignore unscheduled pods before they are a certain age. Values must be an integer followed by a unit ("s" for seconds, "m" for minutes, "h" for hours, etc). | -| [`autoScalerProfileOkTotalUnreadyCount`](#parameter-autoscalerprofileoktotalunreadycount) | string | Specifies the OK total unready count for the auto-scaler of the AKS cluster. | +| [`autoScalerProfileOkTotalUnreadyCount`](#parameter-autoscalerprofileoktotalunreadycount) | int | Specifies the OK total unready count for the auto-scaler of the AKS cluster. | | [`autoScalerProfileScaleDownDelayAfterAdd`](#parameter-autoscalerprofilescaledowndelayafteradd) | string | Specifies the scale down delay after add of the auto-scaler of the AKS cluster. | | [`autoScalerProfileScaleDownDelayAfterDelete`](#parameter-autoscalerprofilescaledowndelayafterdelete) | string | Specifies the scale down delay after delete of the auto-scaler of the AKS cluster. | | [`autoScalerProfileScaleDownDelayAfterFailure`](#parameter-autoscalerprofilescaledowndelayafterfailure) | string | Specifies scale down delay after failure of the auto-scaler of the AKS cluster. | @@ -2481,12 +2481,12 @@ param tags = { | [`loadBalancerSku`](#parameter-loadbalancersku) | string | Specifies the sku of the load balancer used by the virtual machine scale sets used by nodepools. | | [`location`](#parameter-location) | string | Specifies the location of AKS cluster. It picks up Resource Group's location by default. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | -| [`maintenanceConfigurations`](#parameter-maintenanceconfigurations) | array | Maintenance Window for Cluster auto upgrade and node OS upgrade. | +| [`maintenanceConfigurations`](#parameter-maintenanceconfigurations) | array | Whether or not to use AKS Automatic mode. | | [`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. | | [`managedOutboundIPCount`](#parameter-managedoutboundipcount) | int | Outbound IP Count for the Load balancer. | | [`metricAnnotationsAllowList`](#parameter-metricannotationsallowlist) | string | A comma-separated list of Kubernetes cluster metrics annotations. | | [`metricLabelsAllowlist`](#parameter-metriclabelsallowlist) | string | A comma-separated list of kubernetes cluster metrics labels. | -| [`monitoringWorkspaceId`](#parameter-monitoringworkspaceid) | string | Resource ID of the monitoring log analytics workspace. | +| [`monitoringWorkspaceResourceId`](#parameter-monitoringworkspaceresourceid) | string | Resource ID of the monitoring log analytics workspace. | | [`networkDataplane`](#parameter-networkdataplane) | string | Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin. | | [`networkPlugin`](#parameter-networkplugin) | string | Specifies the network plugin used for building Kubernetes network. | | [`networkPluginMode`](#parameter-networkpluginmode) | string | Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin. | @@ -2519,13 +2519,372 @@ Specifies the name of the AKS cluster. - Required: Yes - Type: string -### Parameter: `primaryAgentPoolProfile` +### Parameter: `primaryAgentPoolProfiles` Properties of the primary agent pool. - Required: Yes - Type: array +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-primaryagentpoolprofilesname) | string | The name of the agent pool. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`availabilityZones`](#parameter-primaryagentpoolprofilesavailabilityzones) | array | The availability zones of the agent pool. | +| [`count`](#parameter-primaryagentpoolprofilescount) | int | The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`enableAutoScaling`](#parameter-primaryagentpoolprofilesenableautoscaling) | bool | Whether to enable auto-scaling for the agent pool. | +| [`enableDefaultTelemetry`](#parameter-primaryagentpoolprofilesenabledefaulttelemetry) | bool | The enable default telemetry of the agent pool. | +| [`enableEncryptionAtHost`](#parameter-primaryagentpoolprofilesenableencryptionathost) | bool | Whether to enable encryption at host for the agent pool. | +| [`enableFIPS`](#parameter-primaryagentpoolprofilesenablefips) | bool | Whether to enable FIPS for the agent pool. | +| [`enableNodePublicIP`](#parameter-primaryagentpoolprofilesenablenodepublicip) | bool | Whether to enable node public IP for the agent pool. | +| [`enableUltraSSD`](#parameter-primaryagentpoolprofilesenableultrassd) | bool | Whether to enable Ultra SSD for the agent pool. | +| [`gpuInstanceProfile`](#parameter-primaryagentpoolprofilesgpuinstanceprofile) | string | The GPU instance profile of the agent pool. | +| [`kubeletDiskType`](#parameter-primaryagentpoolprofileskubeletdisktype) | string | The kubelet disk type of the agent pool. | +| [`maxCount`](#parameter-primaryagentpoolprofilesmaxcount) | int | The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`maxPods`](#parameter-primaryagentpoolprofilesmaxpods) | int | The maximum number of pods that can run on a node. | +| [`maxSurge`](#parameter-primaryagentpoolprofilesmaxsurge) | string | The maximum number of nodes that can be created during an upgrade. | +| [`minCount`](#parameter-primaryagentpoolprofilesmincount) | int | The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`minPods`](#parameter-primaryagentpoolprofilesminpods) | int | The minimum number of pods that can run on a node. | +| [`mode`](#parameter-primaryagentpoolprofilesmode) | string | The mode of the agent pool. | +| [`nodeLabels`](#parameter-primaryagentpoolprofilesnodelabels) | object | The node labels of the agent pool. | +| [`nodePublicIpPrefixResourceId`](#parameter-primaryagentpoolprofilesnodepublicipprefixresourceid) | string | The node public IP prefix ID of the agent pool. | +| [`nodeTaints`](#parameter-primaryagentpoolprofilesnodetaints) | array | The node taints of the agent pool. | +| [`orchestratorVersion`](#parameter-primaryagentpoolprofilesorchestratorversion) | string | The Kubernetes version of the agent pool. | +| [`osDiskSizeGB`](#parameter-primaryagentpoolprofilesosdisksizegb) | int | The OS disk size in GB of the agent pool. | +| [`osDiskType`](#parameter-primaryagentpoolprofilesosdisktype) | string | The OS disk type of the agent pool. | +| [`osSku`](#parameter-primaryagentpoolprofilesossku) | string | The OS SKU of the agent pool. | +| [`osType`](#parameter-primaryagentpoolprofilesostype) | string | The OS type of the agent pool. | +| [`podSubnetResourceId`](#parameter-primaryagentpoolprofilespodsubnetresourceid) | string | The pod subnet ID of the agent pool. | +| [`proximityPlacementGroupResourceId`](#parameter-primaryagentpoolprofilesproximityplacementgroupresourceid) | string | The proximity placement group resource ID of the agent pool. | +| [`scaleDownMode`](#parameter-primaryagentpoolprofilesscaledownmode) | string | The scale down mode of the agent pool. | +| [`scaleSetEvictionPolicy`](#parameter-primaryagentpoolprofilesscalesetevictionpolicy) | string | The scale set eviction policy of the agent pool. | +| [`scaleSetPriority`](#parameter-primaryagentpoolprofilesscalesetpriority) | string | The scale set priority of the agent pool. | +| [`sourceResourceId`](#parameter-primaryagentpoolprofilessourceresourceid) | string | The source resource ID to create the agent pool from. | +| [`spotMaxPrice`](#parameter-primaryagentpoolprofilesspotmaxprice) | int | The spot max price of the agent pool. | +| [`tags`](#parameter-primaryagentpoolprofilestags) | object | The tags of the agent pool. | +| [`type`](#parameter-primaryagentpoolprofilestype) | string | The type of the agent pool. | +| [`vmSize`](#parameter-primaryagentpoolprofilesvmsize) | string | The VM size of the agent pool. | +| [`vnetSubnetResourceId`](#parameter-primaryagentpoolprofilesvnetsubnetresourceid) | string | The VNet subnet ID of the agent pool. | +| [`workloadRuntime`](#parameter-primaryagentpoolprofilesworkloadruntime) | string | The workload runtime of the agent pool. | + +### Parameter: `primaryAgentPoolProfiles.name` + +The name of the agent pool. + +- Required: Yes +- Type: string + +### Parameter: `primaryAgentPoolProfiles.availabilityZones` + +The availability zones of the agent pool. + +- Required: No +- Type: array + +### Parameter: `primaryAgentPoolProfiles.count` + +The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `primaryAgentPoolProfiles.enableAutoScaling` + +Whether to enable auto-scaling for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `primaryAgentPoolProfiles.enableDefaultTelemetry` + +The enable default telemetry of the agent pool. + +- Required: No +- Type: bool + +### Parameter: `primaryAgentPoolProfiles.enableEncryptionAtHost` + +Whether to enable encryption at host for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `primaryAgentPoolProfiles.enableFIPS` + +Whether to enable FIPS for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `primaryAgentPoolProfiles.enableNodePublicIP` + +Whether to enable node public IP for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `primaryAgentPoolProfiles.enableUltraSSD` + +Whether to enable Ultra SSD for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `primaryAgentPoolProfiles.gpuInstanceProfile` + +The GPU instance profile of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'MIG1g' + 'MIG2g' + 'MIG3g' + 'MIG4g' + 'MIG7g' + ] + ``` + +### Parameter: `primaryAgentPoolProfiles.kubeletDiskType` + +The kubelet disk type of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.maxCount` + +The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `primaryAgentPoolProfiles.maxPods` + +The maximum number of pods that can run on a node. + +- Required: No +- Type: int + +### Parameter: `primaryAgentPoolProfiles.maxSurge` + +The maximum number of nodes that can be created during an upgrade. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.minCount` + +The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `primaryAgentPoolProfiles.minPods` + +The minimum number of pods that can run on a node. + +- Required: No +- Type: int + +### Parameter: `primaryAgentPoolProfiles.mode` + +The mode of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'System' + 'User' + ] + ``` + +### Parameter: `primaryAgentPoolProfiles.nodeLabels` + +The node labels of the agent pool. + +- Required: No +- Type: object + +### Parameter: `primaryAgentPoolProfiles.nodePublicIpPrefixResourceId` + +The node public IP prefix ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.nodeTaints` + +The node taints of the agent pool. + +- Required: No +- Type: array + +### Parameter: `primaryAgentPoolProfiles.orchestratorVersion` + +The Kubernetes version of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.osDiskSizeGB` + +The OS disk size in GB of the agent pool. + +- Required: No +- Type: int + +### Parameter: `primaryAgentPoolProfiles.osDiskType` + +The OS disk type of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.osSku` + +The OS SKU of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.osType` + +The OS type of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `primaryAgentPoolProfiles.podSubnetResourceId` + +The pod subnet ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.proximityPlacementGroupResourceId` + +The proximity placement group resource ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.scaleDownMode` + +The scale down mode of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Deallocate' + 'Delete' + ] + ``` + +### Parameter: `primaryAgentPoolProfiles.scaleSetEvictionPolicy` + +The scale set eviction policy of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Deallocate' + 'Delete' + ] + ``` + +### Parameter: `primaryAgentPoolProfiles.scaleSetPriority` + +The scale set priority of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Low' + 'Regular' + 'Spot' + ] + ``` + +### Parameter: `primaryAgentPoolProfiles.sourceResourceId` + +The source resource ID to create the agent pool from. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.spotMaxPrice` + +The spot max price of the agent pool. + +- Required: No +- Type: int + +### Parameter: `primaryAgentPoolProfiles.tags` + +The tags of the agent pool. + +- Required: No +- Type: object + +### Parameter: `primaryAgentPoolProfiles.type` + +The type of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AvailabilitySet' + 'VirtualMachineScaleSets' + ] + ``` + +### Parameter: `primaryAgentPoolProfiles.vmSize` + +The VM size of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.vnetSubnetResourceId` + +The VNet subnet ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `primaryAgentPoolProfiles.workloadRuntime` + +The workload runtime of the agent pool. + +- Required: No +- Type: string + ### Parameter: `aksServicePrincipalProfile` Information about a service principal identity for the cluster to use for manipulating Azure APIs. Required if no managed identities are assigned to the cluster. @@ -2642,14 +3001,14 @@ Define one or more secondary/additional agent pools. | [`minPods`](#parameter-agentpoolsminpods) | int | The minimum number of pods that can run on a node. | | [`mode`](#parameter-agentpoolsmode) | string | The mode of the agent pool. | | [`nodeLabels`](#parameter-agentpoolsnodelabels) | object | The node labels of the agent pool. | -| [`nodePublicIpPrefixId`](#parameter-agentpoolsnodepublicipprefixid) | string | The node public IP prefix ID of the agent pool. | +| [`nodePublicIpPrefixResourceId`](#parameter-agentpoolsnodepublicipprefixresourceid) | string | The node public IP prefix ID of the agent pool. | | [`nodeTaints`](#parameter-agentpoolsnodetaints) | array | The node taints of the agent pool. | | [`orchestratorVersion`](#parameter-agentpoolsorchestratorversion) | string | The Kubernetes version of the agent pool. | | [`osDiskSizeGB`](#parameter-agentpoolsosdisksizegb) | int | The OS disk size in GB of the agent pool. | | [`osDiskType`](#parameter-agentpoolsosdisktype) | string | The OS disk type of the agent pool. | | [`osSku`](#parameter-agentpoolsossku) | string | The OS SKU of the agent pool. | | [`osType`](#parameter-agentpoolsostype) | string | The OS type of the agent pool. | -| [`podSubnetId`](#parameter-agentpoolspodsubnetid) | string | The pod subnet ID of the agent pool. | +| [`podSubnetResourceId`](#parameter-agentpoolspodsubnetresourceid) | string | The pod subnet ID of the agent pool. | | [`proximityPlacementGroupResourceId`](#parameter-agentpoolsproximityplacementgroupresourceid) | string | The proximity placement group resource ID of the agent pool. | | [`scaleDownMode`](#parameter-agentpoolsscaledownmode) | string | The scale down mode of the agent pool. | | [`scaleSetEvictionPolicy`](#parameter-agentpoolsscalesetevictionpolicy) | string | The scale set eviction policy of the agent pool. | @@ -2659,14 +3018,14 @@ Define one or more secondary/additional agent pools. | [`tags`](#parameter-agentpoolstags) | object | The tags of the agent pool. | | [`type`](#parameter-agentpoolstype) | string | The type of the agent pool. | | [`vmSize`](#parameter-agentpoolsvmsize) | string | The VM size of the agent pool. | -| [`vnetSubnetID`](#parameter-agentpoolsvnetsubnetid) | string | The VNet subnet ID of the agent pool. | +| [`vnetSubnetResourceId`](#parameter-agentpoolsvnetsubnetresourceid) | string | The VNet subnet ID of the agent pool. | | [`workloadRuntime`](#parameter-agentpoolsworkloadruntime) | string | The workload runtime of the agent pool. | ### Parameter: `agentPools.name` The name of the agent pool. -- Required: No +- Required: Yes - Type: string ### Parameter: `agentPools.availabilityZones` @@ -2805,7 +3164,7 @@ The node labels of the agent pool. - Required: No - Type: object -### Parameter: `agentPools.nodePublicIpPrefixId` +### Parameter: `agentPools.nodePublicIpPrefixResourceId` The node public IP prefix ID of the agent pool. @@ -2861,7 +3220,7 @@ The OS type of the agent pool. ] ``` -### Parameter: `agentPools.podSubnetId` +### Parameter: `agentPools.podSubnetResourceId` The pod subnet ID of the agent pool. @@ -2960,7 +3319,7 @@ The VM size of the agent pool. - Required: No - Type: string -### Parameter: `agentPools.vnetSubnetID` +### Parameter: `agentPools.vnetSubnetResourceId` The VNet subnet ID of the agent pool. @@ -3028,16 +3387,16 @@ Specifies the expand strategy for the auto-scaler of the AKS cluster. Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster. - Required: No -- Type: string -- Default: `'10'` +- Type: int +- Default: `10` ### Parameter: `autoScalerProfileMaxGracefulTerminationSec` Specifies the max graceful termination time interval in seconds for the auto-scaler of the AKS cluster. - Required: No -- Type: string -- Default: `'600'` +- Type: int +- Default: `600` ### Parameter: `autoScalerProfileMaxNodeProvisionTime` @@ -3052,8 +3411,8 @@ Specifies the maximum node provisioning time for the auto-scaler of the AKS clus Specifies the mximum total unready percentage for the auto-scaler of the AKS cluster. The maximum is 100 and the minimum is 0. - Required: No -- Type: string -- Default: `'45'` +- Type: int +- Default: `45` ### Parameter: `autoScalerProfileNewPodScaleUpDelay` @@ -3068,8 +3427,8 @@ For scenarios like burst/batch scale where you do not want CA to act before the Specifies the OK total unready count for the auto-scaler of the AKS cluster. - Required: No -- Type: string -- Default: `'3'` +- Type: int +- Default: `3` ### Parameter: `autoScalerProfileScaleDownDelayAfterAdd` @@ -3416,7 +3775,7 @@ If set to true, getting static credentials will be disabled for this cluster. Th - Required: No - Type: bool -- Default: `False` +- Default: `True` ### Parameter: `disablePrometheusMetricsScraping` @@ -3823,7 +4182,7 @@ Specify the name of lock. ### Parameter: `maintenanceConfigurations` -Maintenance Window for Cluster auto upgrade and node OS upgrade. +Whether or not to use AKS Automatic mode. - Required: No - Type: array @@ -3908,7 +4267,7 @@ A comma-separated list of kubernetes cluster metrics labels. - Type: string - Default: `''` -### Parameter: `monitoringWorkspaceId` +### Parameter: `monitoringWorkspaceResourceId` Resource ID of the monitoring log analytics workspace. diff --git a/avm/res/container-service/managed-cluster/agent-pool/README.md b/avm/res/container-service/managed-cluster/agent-pool/README.md index b83fb64af6..67ac41ab37 100644 --- a/avm/res/container-service/managed-cluster/agent-pool/README.md +++ b/avm/res/container-service/managed-cluster/agent-pool/README.md @@ -47,14 +47,14 @@ This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Agent Pool | [`minCount`](#parameter-mincount) | int | The minimum number of nodes for auto-scaling. | | [`mode`](#parameter-mode) | string | A cluster must have at least one "System" Agent Pool at all times. For additional information on agent pool restrictions and best practices, see: /azure/aks/use-system-pools. | | [`nodeLabels`](#parameter-nodelabels) | object | The node labels to be persisted across all nodes in agent pool. | -| [`nodePublicIpPrefixId`](#parameter-nodepublicipprefixid) | string | ResourceId of the node PublicIPPrefix. | +| [`nodePublicIpPrefixResourceId`](#parameter-nodepublicipprefixresourceid) | string | ResourceId of the node PublicIPPrefix. | | [`nodeTaints`](#parameter-nodetaints) | array | The taints added to new nodes during node pool create and scale. For example, key=value:NoSchedule. | | [`orchestratorVersion`](#parameter-orchestratorversion) | string | As a best practice, you should upgrade all node pools in an AKS cluster to the same Kubernetes version. The node pool version must have the same major version as the control plane. The node pool minor version must be within two minor versions of the control plane version. The node pool version cannot be greater than the control plane version. For more information see upgrading a node pool (https://learn.microsoft.com/en-us/azure/aks/use-multiple-node-pools#upgrade-a-node-pool). | | [`osDiskSizeGB`](#parameter-osdisksizegb) | int | OS Disk Size in GB to be used to specify the disk size for every machine in the master/agent pool. If you specify 0, it will apply the default osDisk size according to the vmSize specified. | | [`osDiskType`](#parameter-osdisktype) | string | The default is "Ephemeral" if the VM supports it and has a cache disk larger than the requested OSDiskSizeGB. Otherwise, defaults to "Managed". May not be changed after creation. For more information see Ephemeral OS (https://learn.microsoft.com/en-us/azure/aks/cluster-configuration#ephemeral-os). | | [`osSku`](#parameter-ossku) | string | Specifies the OS SKU used by the agent pool. The default is Ubuntu if OSType is Linux. The default is Windows2019 when Kubernetes <= 1.24 or Windows2022 when Kubernetes >= 1.25 if OSType is Windows. | | [`osType`](#parameter-ostype) | string | The operating system type. The default is Linux. | -| [`podSubnetId`](#parameter-podsubnetid) | string | Subnet ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}. | +| [`podSubnetResourceId`](#parameter-podsubnetresourceid) | string | Subnet resource ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}. | | [`proximityPlacementGroupResourceId`](#parameter-proximityplacementgroupresourceid) | string | The ID for the Proximity Placement Group. | | [`scaleDownMode`](#parameter-scaledownmode) | string | Describes how VMs are added to or removed from Agent Pools. See [billing states](https://learn.microsoft.com/en-us/azure/virtual-machines/states-billing). | | [`scaleSetEvictionPolicy`](#parameter-scalesetevictionpolicy) | string | The eviction policy specifies what to do with the VM when it is evicted. The default is Delete. For more information about eviction see spot VMs. | @@ -64,7 +64,7 @@ This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Agent Pool | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`type`](#parameter-type) | string | The type of Agent Pool. | | [`vmSize`](#parameter-vmsize) | string | VM size. VM size availability varies by region. If a node contains insufficient compute resources (memory, cpu, etc) pods might fail to run correctly. For more details on restricted VM sizes, see: /azure/aks/quotas-skus-regions. | -| [`vnetSubnetId`](#parameter-vnetsubnetid) | string | Node Subnet ID. If this is not specified, a VNET and subnet will be generated and used. If no podSubnetID is specified, this applies to nodes and pods, otherwise it applies to just nodes. This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}. | +| [`vnetSubnetResourceId`](#parameter-vnetsubnetresourceid) | string | Node Subnet ID. If this is not specified, a VNET and subnet will be generated and used. If no podSubnetID is specified, this applies to nodes and pods, otherwise it applies to just nodes. This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}. | | [`workloadRuntime`](#parameter-workloadruntime) | string | Determines the type of workload a node can run. | ### Parameter: `name` @@ -87,6 +87,14 @@ The list of Availability zones to use for nodes. This can only be specified if t - Required: No - Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` ### Parameter: `count` @@ -202,7 +210,7 @@ The node labels to be persisted across all nodes in agent pool. - Required: No - Type: object -### Parameter: `nodePublicIpPrefixId` +### Parameter: `nodePublicIpPrefixResourceId` ResourceId of the node PublicIPPrefix. @@ -276,9 +284,9 @@ The operating system type. The default is Linux. ] ``` -### Parameter: `podSubnetId` +### Parameter: `podSubnetResourceId` -Subnet ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}. +Subnet resource ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}. - Required: No - Type: string @@ -370,7 +378,7 @@ VM size. VM size availability varies by region. If a node contains insufficient - Type: string - Default: `'Standard_D2s_v3'` -### Parameter: `vnetSubnetId` +### Parameter: `vnetSubnetResourceId` Node Subnet ID. If this is not specified, a VNET and subnet will be generated and used. If no podSubnetID is specified, this applies to nodes and pods, otherwise it applies to just nodes. This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}. diff --git a/avm/res/container-service/managed-cluster/agent-pool/main.bicep b/avm/res/container-service/managed-cluster/agent-pool/main.bicep index 0a79a28c61..e5ae30e13d 100644 --- a/avm/res/container-service/managed-cluster/agent-pool/main.bicep +++ b/avm/res/container-service/managed-cluster/agent-pool/main.bicep @@ -9,7 +9,7 @@ param managedClusterName string param name string @description('Optional. The list of Availability zones to use for nodes. This can only be specified if the AgentPoolType property is "VirtualMachineScaleSets".') -param availabilityZones array? +param availabilityZones int[] = [1, 2, 3] @description('Optional. Desired Number of agents (VMs) specified to host docker containers. Allowed values must be in the range of 0 to 1000 (inclusive) for user pools and in the range of 1 to 1000 (inclusive) for system pools. The default value is 1.') @minValue(0) @@ -63,7 +63,7 @@ param mode string? param nodeLabels object? @description('Optional. ResourceId of the node PublicIPPrefix.') -param nodePublicIpPrefixId string? +param nodePublicIpPrefixResourceId string? @description('Optional. The taints added to new nodes during node pool create and scale. For example, key=value:NoSchedule.') param nodeTaints array? @@ -98,8 +98,8 @@ param osSku string? ]) param osType string = 'Linux' -@description('Optional. Subnet ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}.') -param podSubnetId string? +@description('Optional. Subnet resource ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}.') +param podSubnetResourceId string? @description('Optional. The ID for the Proximity Placement Group.') param proximityPlacementGroupResourceId string? @@ -141,7 +141,7 @@ param maxSurge string? param vmSize string = 'Standard_D2s_v3' @description('Optional. Node Subnet ID. If this is not specified, a VNET and subnet will be generated and used. If no podSubnetID is specified, this applies to nodes and pods, otherwise it applies to just nodes. This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}.') -param vnetSubnetId string? +param vnetSubnetResourceId string? @description('Optional. Determines the type of workload a node can run.') param workloadRuntime string? @@ -154,7 +154,7 @@ resource agentPool 'Microsoft.ContainerService/managedClusters/agentPools@2023-0 name: name parent: managedCluster properties: { - availabilityZones: availabilityZones + availabilityZones: map(availabilityZones ?? [], zone => '${zone}') count: count creationData: !empty(sourceResourceId) ? { @@ -173,14 +173,14 @@ resource agentPool 'Microsoft.ContainerService/managedClusters/agentPools@2023-0 minCount: minCount mode: mode nodeLabels: nodeLabels - nodePublicIPPrefixID: nodePublicIpPrefixId + nodePublicIPPrefixID: nodePublicIpPrefixResourceId nodeTaints: nodeTaints orchestratorVersion: orchestratorVersion osDiskSizeGB: osDiskSizeGB osDiskType: osDiskType osSKU: osSku osType: osType - podSubnetID: podSubnetId + podSubnetID: podSubnetResourceId proximityPlacementGroupID: proximityPlacementGroupResourceId scaleDownMode: scaleDownMode scaleSetEvictionPolicy: scaleSetEvictionPolicy @@ -192,7 +192,7 @@ resource agentPool 'Microsoft.ContainerService/managedClusters/agentPools@2023-0 maxSurge: maxSurge } vmSize: vmSize - vnetSubnetID: vnetSubnetId + vnetSubnetID: vnetSubnetResourceId workloadRuntime: workloadRuntime } } diff --git a/avm/res/container-service/managed-cluster/agent-pool/main.json b/avm/res/container-service/managed-cluster/agent-pool/main.json index d8141c2a61..65a21588ad 100644 --- a/avm/res/container-service/managed-cluster/agent-pool/main.json +++ b/avm/res/container-service/managed-cluster/agent-pool/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2004205618690542488" + "version": "0.30.23.60470", + "templateHash": "13856766172443517827" }, "name": "Azure Kubernetes Service (AKS) Managed Cluster Agent Pools", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Agent Pool.", @@ -27,7 +27,14 @@ }, "availabilityZones": { "type": "array", - "nullable": true, + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], "metadata": { "description": "Optional. The list of Availability zones to use for nodes. This can only be specified if the AgentPoolType property is \"VirtualMachineScaleSets\"." } @@ -139,7 +146,7 @@ "description": "Optional. The node labels to be persisted across all nodes in agent pool." } }, - "nodePublicIpPrefixId": { + "nodePublicIpPrefixResourceId": { "type": "string", "nullable": true, "metadata": { @@ -203,11 +210,11 @@ "description": "Optional. The operating system type. The default is Linux." } }, - "podSubnetId": { + "podSubnetResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Subnet ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." + "description": "Optional. Subnet resource ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." } }, "proximityPlacementGroupResourceId": { @@ -285,7 +292,7 @@ "description": "Optional. VM size. VM size availability varies by region. If a node contains insufficient compute resources (memory, cpu, etc) pods might fail to run correctly. For more details on restricted VM sizes, see: /azure/aks/quotas-skus-regions." } }, - "vnetSubnetId": { + "vnetSubnetResourceId": { "type": "string", "nullable": true, "metadata": { @@ -312,7 +319,7 @@ "apiVersion": "2023-07-02-preview", "name": "[format('{0}/{1}', parameters('managedClusterName'), parameters('name'))]", "properties": { - "availabilityZones": "[parameters('availabilityZones')]", + "availabilityZones": "[map(coalesce(parameters('availabilityZones'), createArray()), lambda('zone', format('{0}', lambdaVariables('zone'))))]", "count": "[parameters('count')]", "creationData": "[if(not(empty(parameters('sourceResourceId'))), createObject('sourceResourceId', parameters('sourceResourceId')), null())]", "enableAutoScaling": "[parameters('enableAutoScaling')]", @@ -327,14 +334,14 @@ "minCount": "[parameters('minCount')]", "mode": "[parameters('mode')]", "nodeLabels": "[parameters('nodeLabels')]", - "nodePublicIPPrefixID": "[parameters('nodePublicIpPrefixId')]", + "nodePublicIPPrefixID": "[parameters('nodePublicIpPrefixResourceId')]", "nodeTaints": "[parameters('nodeTaints')]", "orchestratorVersion": "[parameters('orchestratorVersion')]", "osDiskSizeGB": "[parameters('osDiskSizeGB')]", "osDiskType": "[parameters('osDiskType')]", "osSKU": "[parameters('osSku')]", "osType": "[parameters('osType')]", - "podSubnetID": "[parameters('podSubnetId')]", + "podSubnetID": "[parameters('podSubnetResourceId')]", "proximityPlacementGroupID": "[parameters('proximityPlacementGroupResourceId')]", "scaleDownMode": "[parameters('scaleDownMode')]", "scaleSetEvictionPolicy": "[parameters('scaleSetEvictionPolicy')]", @@ -346,7 +353,7 @@ "maxSurge": "[parameters('maxSurge')]" }, "vmSize": "[parameters('vmSize')]", - "vnetSubnetID": "[parameters('vnetSubnetId')]", + "vnetSubnetID": "[parameters('vnetSubnetResourceId')]", "workloadRuntime": "[parameters('workloadRuntime')]" }, "dependsOn": [ diff --git a/avm/res/container-service/managed-cluster/main.bicep b/avm/res/container-service/managed-cluster/main.bicep index 555b07cab8..88a8d6a89b 100644 --- a/avm/res/container-service/managed-cluster/main.bicep +++ b/avm/res/container-service/managed-cluster/main.bicep @@ -12,7 +12,7 @@ param location string = resourceGroup().location param dnsPrefix string = name @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 managedIdentitiesType +param managedIdentities managedIdentitiesType? @description('Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin.') @allowed([ @@ -110,7 +110,7 @@ param aadProfileServerAppSecret string? param aadProfileTenantId string = subscription().tenantId @description('Optional. Specifies the AAD group object IDs that will have admin role of the cluster.') -param aadProfileAdminGroupObjectIDs array? +param aadProfileAdminGroupObjectIDs string[]? @description('Optional. Specifies whether to enable managed AAD integration.') param aadProfileManaged bool = true @@ -122,13 +122,13 @@ param enableRBAC bool = true param aadProfileEnableAzureRBAC bool = enableRBAC @description('Optional. If set to true, getting static credentials will be disabled for this cluster. This must only be used on Managed Clusters that are AAD enabled.') -param disableLocalAccounts bool = false +param disableLocalAccounts bool = true @description('Optional. Name of the resource group containing agent pool nodes.') param nodeResourceGroup string = '${resourceGroup().name}_aks_${name}_nodes' @description('Optional. IP ranges are specified in CIDR format, e.g. 137.117.106.88/29. This feature is not compatible with clusters that use Public IP Per Node, or clusters that are using a Basic Load Balancer.') -param authorizedIPRanges array? +param authorizedIPRanges string[]? @description('Optional. Whether to disable run command for the cluster or not.') param disableRunCommand bool = false @@ -151,13 +151,13 @@ param enablePrivateClusterPublicFQDN bool = false param privateDNSZone string? @description('Required. Properties of the primary agent pool.') -param primaryAgentPoolProfile array +param primaryAgentPoolProfiles agentPoolType[] @description('Optional. Define one or more secondary/additional agent pools.') -param agentPools agentPoolType +param agentPools agentPoolType[]? -@description('Optional. Maintenance Window for Cluster auto upgrade and node OS upgrade.') -param maintenanceConfigurations maintenanceConfigurationType +@description('Optional. Whether or not to use AKS Automatic mode.') +param maintenanceConfigurations maintenanceConfigurationType[]? @description('Optional. Specifies whether the cost analysis add-on is enabled or not. If Enabled `enableStorageProfileDiskCSIDriver` is set to true as it is needed.') param costAnalysisEnabled bool = false @@ -225,7 +225,7 @@ param autoScalerProfileScaleDownUnreadyTime string = '20m' param autoScalerProfileUtilizationThreshold string = '0.5' @description('Optional. Specifies the max graceful termination time interval in seconds for the auto-scaler of the AKS cluster.') -param autoScalerProfileMaxGracefulTerminationSec string = '600' +param autoScalerProfileMaxGracefulTerminationSec int = 600 @description('Optional. Specifies the balance of similar node groups for the auto-scaler of the AKS cluster.') param autoScalerProfileBalanceSimilarNodeGroups bool = false @@ -240,19 +240,19 @@ param autoScalerProfileBalanceSimilarNodeGroups bool = false param autoScalerProfileExpander string = 'random' @description('Optional. Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster.') -param autoScalerProfileMaxEmptyBulkDelete string = '10' +param autoScalerProfileMaxEmptyBulkDelete int = 10 @description('Optional. Specifies the maximum node provisioning time for the auto-scaler of the AKS cluster. Values must be an integer followed by an "m". No unit of time other than minutes (m) is supported.') param autoScalerProfileMaxNodeProvisionTime string = '15m' @description('Optional. Specifies the mximum total unready percentage for the auto-scaler of the AKS cluster. The maximum is 100 and the minimum is 0.') -param autoScalerProfileMaxTotalUnreadyPercentage string = '45' +param autoScalerProfileMaxTotalUnreadyPercentage int = 45 @description('Optional. For scenarios like burst/batch scale where you do not want CA to act before the kubernetes scheduler could schedule all the pods, you can tell CA to ignore unscheduled pods before they are a certain age. Values must be an integer followed by a unit ("s" for seconds, "m" for minutes, "h" for hours, etc).') param autoScalerProfileNewPodScaleUpDelay string = '0s' @description('Optional. Specifies the OK total unready count for the auto-scaler of the AKS cluster.') -param autoScalerProfileOkTotalUnreadyCount string = '3' +param autoScalerProfileOkTotalUnreadyCount int = 3 @description('Optional. Specifies if nodes with local storage should be skipped for the auto-scaler of the AKS cluster.') param autoScalerProfileSkipNodesWithLocalStorage bool = true @@ -336,7 +336,7 @@ param diagnosticSettings diagnosticSettingType param omsAgentEnabled bool = true @description('Optional. Resource ID of the monitoring log analytics workspace.') -param monitoringWorkspaceId string? +param monitoringWorkspaceResourceId string? @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true @@ -354,7 +354,7 @@ param tags object? param diskEncryptionSetResourceId string? @description('Optional. Settings and configurations for the flux extension.') -param fluxExtension extensionType +param fluxExtension extensionType? @description('Optional. Configurations for provisioning the cluster with HTTP proxy servers.') param httpProxyConfig object? @@ -369,7 +369,7 @@ param kedaAddon bool = false param vpaAddon bool = false @description('Optional. The customer managed key definition.') -param customerManagedKey customerManagedKeyType +param customerManagedKey customerManagedKeyType? @description('Optional. Whether the metric state of the kubenetes cluster is enabled.') param enableAzureMonitorProfileMetrics bool = false @@ -541,12 +541,58 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p tier: skuTier } properties: { + agentPoolProfiles: map(primaryAgentPoolProfiles, profile => { + name: profile.name + count: profile.count ?? 1 + availabilityZones: map(profile.?availabilityZones ?? [1, 2, 3], zone => '${zone}') + creationData: !empty(profile.?sourceResourceId) + ? { + #disable-next-line use-resource-id-functions // Not possible to reference as nested + sourceResourceId: profile.sourceResourceId + } + : null + enableAutoScaling: profile.?enableAutoScaling ?? false + enableEncryptionAtHost: profile.?enableEncryptionAtHost ?? false + enableFIPS: profile.?enableFIPS ?? false + enableNodePublicIP: profile.?enableNodePublicIP ?? false + enableUltraSSD: profile.?enableUltraSSD ?? false + gpuInstanceProfile: profile.?gpuInstanceProfile + kubeletDiskType: profile.?kubeletDiskType + maxCount: profile.?maxCount + maxPods: profile.?maxPods + minCount: profile.?minCount + mode: profile.?mode + nodeLabels: profile.?nodeLabels + #disable-next-line use-resource-id-functions // Not possible to reference as nested + nodePublicIPPrefixID: profile.?nodePublicIpPrefixResourceId + nodeTaints: profile.?nodeTaints + orchestratorVersion: profile.?orchestratorVersion + osDiskSizeGB: profile.?osDiskSizeGB + osDiskType: profile.?osDiskType + osType: profile.?osType ?? 'Linux' + #disable-next-line use-resource-id-functions // Not possible to reference as nested + podSubnetID: profile.?podSubnetResourceId + #disable-next-line use-resource-id-functions // Not possible to reference as nested + proximityPlacementGroupID: profile.?proximityPlacementGroupResourceId + scaleDownMode: profile.?scaleDownMode ?? 'Delete' + scaleSetEvictionPolicy: profile.?scaleSetEvictionPolicy ?? 'Delete' + scaleSetPriority: profile.?scaleSetPriority + spotMaxPrice: profile.?spotMaxPrice + tags: profile.?tags + type: profile.?type + upgradeSettings: { + maxSurge: profile.?maxSurge + } + vmSize: profile.?vmSize ?? 'Standard_D2s_v3' + #disable-next-line use-resource-id-functions // Not possible to reference as nested + vnetSubnetID: profile.?vnetSubnetResourceId + workloadRuntime: profile.?workloadRuntime + }) httpProxyConfig: httpProxyConfig identityProfile: identityProfile diskEncryptionSetID: diskEncryptionSetResourceId kubernetesVersion: kubernetesVersion dnsPrefix: dnsPrefix - agentPoolProfiles: primaryAgentPoolProfile linuxProfile: !empty(sshPublicKey) ? { adminUsername: adminUsername @@ -590,11 +636,10 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p : null } omsagent: { - enabled: omsAgentEnabled && !empty(monitoringWorkspaceId) - #disable-next-line BCP321 // Value will not be used if null or empty - config: omsAgentEnabled && !empty(monitoringWorkspaceId) + enabled: omsAgentEnabled && !empty(monitoringWorkspaceResourceId) + config: omsAgentEnabled && !empty(monitoringWorkspaceResourceId) ? { - logAnalyticsWorkspaceResourceID: monitoringWorkspaceId + logAnalyticsWorkspaceResourceID: monitoringWorkspaceResourceId! } : null } @@ -675,12 +720,12 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p autoScalerProfile: { 'balance-similar-node-groups': toLower(string(autoScalerProfileBalanceSimilarNodeGroups)) expander: autoScalerProfileExpander - 'max-empty-bulk-delete': autoScalerProfileMaxEmptyBulkDelete - 'max-graceful-termination-sec': autoScalerProfileMaxGracefulTerminationSec + 'max-empty-bulk-delete': '${autoScalerProfileMaxEmptyBulkDelete}' + 'max-graceful-termination-sec': '${autoScalerProfileMaxGracefulTerminationSec}' 'max-node-provision-time': autoScalerProfileMaxNodeProvisionTime - 'max-total-unready-percentage': autoScalerProfileMaxTotalUnreadyPercentage + 'max-total-unready-percentage': '${autoScalerProfileMaxTotalUnreadyPercentage}' 'new-pod-scale-up-delay': autoScalerProfileNewPodScaleUpDelay - 'ok-total-unready-count': autoScalerProfileOkTotalUnreadyCount + 'ok-total-unready-count': '${autoScalerProfileOkTotalUnreadyCount}' 'scale-down-delay-after-add': autoScalerProfileScaleDownDelayAfterAdd 'scale-down-delay-after-delete': autoScalerProfileScaleDownDelayAfterDelete 'scale-down-delay-after-failure': autoScalerProfileScaleDownDelayAfterFailure @@ -706,7 +751,9 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p containerInsights: enableContainerInsights ? { enabled: enableContainerInsights - logAnalyticsWorkspaceResourceId: !empty(monitoringWorkspaceId) ? monitoringWorkspaceId : null + logAnalyticsWorkspaceResourceId: !empty(monitoringWorkspaceResourceId) + ? monitoringWorkspaceResourceId + : null disableCustomMetrics: disableCustomMetrics disablePrometheusMetricsScraping: disablePrometheusMetricsScraping syslogPort: syslogPort @@ -734,7 +781,7 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p securityMonitoring: { enabled: enableAzureDefender } - logAnalyticsWorkspaceResourceId: monitoringWorkspaceId + logAnalyticsWorkspaceResourceId: monitoringWorkspaceResourceId } : null workloadIdentity: enableWorkloadIdentity @@ -768,8 +815,8 @@ resource managedCluster 'Microsoft.ContainerService/managedClusters@2024-03-02-p } module managedCluster_maintenanceConfigurations 'maintenance-configurations/main.bicep' = [ - for (maintenanceConfiguration, index) in (maintenanceConfigurations ?? []): if (!empty(maintenanceConfiguration)) { - name: '${uniqueString(deployment().name, location)}-ManagedCluster-MaintenanceConfigurations-${index}' + for (maintenanceConfiguration, index) in (maintenanceConfigurations ?? []): { + name: '${uniqueString(deployment().name, location)}-ManagedCluster-MaintenanceConfiguration-${index}' params: { name: maintenanceConfiguration!.name maintenanceWindow: maintenanceConfiguration!.maintenanceWindow @@ -799,14 +846,14 @@ module managedCluster_agentPools 'agent-pool/main.bicep' = [ minCount: agentPool.?minCount mode: agentPool.?mode nodeLabels: agentPool.?nodeLabels - nodePublicIpPrefixId: agentPool.?nodePublicIpPrefixId + nodePublicIpPrefixResourceId: agentPool.?nodePublicIpPrefixResourceId nodeTaints: agentPool.?nodeTaints orchestratorVersion: agentPool.?orchestratorVersion ?? kubernetesVersion osDiskSizeGB: agentPool.?osDiskSizeGB osDiskType: agentPool.?osDiskType osSku: agentPool.?osSku osType: agentPool.?osType - podSubnetId: agentPool.?podSubnetId + podSubnetResourceId: agentPool.?podSubnetResourceId proximityPlacementGroupResourceId: agentPool.?proximityPlacementGroupResourceId scaleDownMode: agentPool.?scaleDownMode scaleSetEvictionPolicy: agentPool.?scaleSetEvictionPolicy @@ -816,7 +863,7 @@ module managedCluster_agentPools 'agent-pool/main.bicep' = [ type: agentPool.?type maxSurge: agentPool.?maxSurge vmSize: agentPool.?vmSize - vnetSubnetId: agentPool.?vnetSubnetId + vnetSubnetResourceId: agentPool.?vnetSubnetResourceId workloadRuntime: agentPool.?workloadRuntime } } @@ -970,12 +1017,13 @@ output webAppRoutingIdentityObjectId string = managedCluster.properties.?ingress // Definitions // // =============== // +@export() type agentPoolType = { @description('Required. The name of the agent pool.') - name: string? + name: string @description('Optional. The availability zones of the agent pool.') - availabilityZones: string[]? + availabilityZones: int[]? @description('Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive).') count: int? @@ -1023,7 +1071,7 @@ type agentPoolType = { nodeLabels: object? @description('Optional. The node public IP prefix ID of the agent pool.') - nodePublicIpPrefixId: string? + nodePublicIpPrefixResourceId: string? @description('Optional. The node taints of the agent pool.') nodeTaints: string[]? @@ -1044,7 +1092,7 @@ type agentPoolType = { osType: ('Linux' | 'Windows')? @description('Optional. The pod subnet ID of the agent pool.') - podSubnetId: string? + podSubnetResourceId: string? @description('Optional. The proximity placement group resource ID of the agent pool.') proximityPlacementGroupResourceId: string? @@ -1074,23 +1122,25 @@ type agentPoolType = { vmSize: string? @description('Optional. The VNet subnet ID of the agent pool.') - vnetSubnetID: string? + vnetSubnetResourceId: string? @description('Optional. The workload runtime of the agent pool.') workloadRuntime: string? @description('Optional. The enable default telemetry of the agent pool.') enableDefaultTelemetry: bool? -}[]? +} +@export() 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.') userAssignedResourcesIds: string[]? -}? +} +@export() type lockType = { @description('Optional. Specify the name of lock.') name: string? @@ -1099,6 +1149,7 @@ type lockType = { kind: ('CanNotDelete' | 'ReadOnly' | 'None')? }? +@export() type roleAssignmentType = { @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') name: string? @@ -1125,6 +1176,7 @@ type roleAssignmentType = { delegatedManagedIdentityResourceId: string? }[]? +@export() type diagnosticSettingType = { @description('Optional. The name of diagnostic setting.') name: string? @@ -1169,11 +1221,13 @@ type diagnosticSettingType = { marketplacePartnerResourceId: string? }[]? +@export() type fluxConfigurationProtectedSettingsType = { @description('Optional. The SSH private key to use for Git authentication.') sshPrivateKey: string? -}? +} +@export() type extensionType = { @description('Required. The name of the extension.') name: string? @@ -1198,8 +1252,9 @@ type extensionType = { @description('Optional. The flux configurations of the extension.') configurations: array? -}? +} +@export() type customerManagedKeyType = { @description('Required. The resource ID of a key vault to reference a customer managed key for encryption from.') keyVaultResourceId: string @@ -1212,12 +1267,13 @@ type customerManagedKeyType = { @description('Required. Network access of key vault. The possible values are Public and Private. Public means the key vault allows public access from all networks. Private means the key vault disables public access and enables private link. The default value is Public.') keyVaultNetworkAccess: ('Private' | 'Public') -}? +} +@export() type maintenanceConfigurationType = { @description('Required. Name of maintenance window.') name: ('aksManagedAutoUpgradeSchedule' | 'aksManagedNodeOSUpgradeSchedule') @description('Required. Maintenance window for the maintenance configuration.') maintenanceWindow: object -}[]? +} diff --git a/avm/res/container-service/managed-cluster/main.json b/avm/res/container-service/managed-cluster/main.json index 142cc567ba..c0c9f95d89 100644 --- a/avm/res/container-service/managed-cluster/main.json +++ b/avm/res/container-service/managed-cluster/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "13565722664676041295" + "templateHash": "14675004991337717729" }, "name": "Azure Kubernetes Service (AKS) Managed Clusters", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster.", @@ -14,310 +14,308 @@ }, "definitions": { "agentPoolType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. The name of the agent pool." - } - }, - "availabilityZones": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The availability zones of the agent pool." - } - }, - "count": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." - } - }, - "sourceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source resource ID to create the agent pool from." - } - }, - "enableAutoScaling": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether to enable auto-scaling for the agent pool." - } - }, - "enableEncryptionAtHost": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether to enable encryption at host for the agent pool." - } - }, - "enableFIPS": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether to enable FIPS for the agent pool." - } - }, - "enableNodePublicIP": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether to enable node public IP for the agent pool." - } - }, - "enableUltraSSD": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether to enable Ultra SSD for the agent pool." - } - }, - "gpuInstanceProfile": { - "type": "string", - "allowedValues": [ - "MIG1g", - "MIG2g", - "MIG3g", - "MIG4g", - "MIG7g" - ], - "nullable": true, - "metadata": { - "description": "Optional. The GPU instance profile of the agent pool." - } - }, - "kubeletDiskType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The kubelet disk type of the agent pool." - } - }, - "maxCount": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." - } - }, - "minCount": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." - } - }, - "maxPods": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum number of pods that can run on a node." - } - }, - "minPods": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The minimum number of pods that can run on a node." - } - }, - "mode": { - "type": "string", - "allowedValues": [ - "System", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The mode of the agent pool." - } - }, - "nodeLabels": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The node labels of the agent pool." - } - }, - "nodePublicIpPrefixId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The node public IP prefix ID of the agent pool." - } - }, - "nodeTaints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The node taints of the agent pool." - } - }, - "orchestratorVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Kubernetes version of the agent pool." - } - }, - "osDiskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The OS disk size in GB of the agent pool." - } - }, - "osDiskType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The OS disk type of the agent pool." - } - }, - "osSku": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The OS SKU of the agent pool." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Linux", - "Windows" - ], - "nullable": true, - "metadata": { - "description": "Optional. The OS type of the agent pool." - } - }, - "podSubnetId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The pod subnet ID of the agent pool." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The proximity placement group resource ID of the agent pool." - } - }, - "scaleDownMode": { - "type": "string", - "allowedValues": [ - "Deallocate", - "Delete" - ], - "nullable": true, - "metadata": { - "description": "Optional. The scale down mode of the agent pool." - } - }, - "scaleSetEvictionPolicy": { - "type": "string", - "allowedValues": [ - "Deallocate", - "Delete" - ], - "nullable": true, - "metadata": { - "description": "Optional. The scale set eviction policy of the agent pool." - } - }, - "scaleSetPriority": { - "type": "string", - "allowedValues": [ - "Low", - "Regular", - "Spot" - ], - "nullable": true, - "metadata": { - "description": "Optional. The scale set priority of the agent pool." - } - }, - "spotMaxPrice": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The spot max price of the agent pool." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags of the agent pool." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "AvailabilitySet", - "VirtualMachineScaleSets" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the agent pool." - } - }, - "maxSurge": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The maximum number of nodes that can be created during an upgrade." - } - }, - "vmSize": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The VM size of the agent pool." - } - }, - "vnetSubnetID": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The VNet subnet ID of the agent pool." - } + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the agent pool." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "int" }, - "workloadRuntime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The workload runtime of the agent pool." - } + "nullable": true, + "metadata": { + "description": "Optional. The availability zones of the agent pool." + } + }, + "count": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "sourceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source resource ID to create the agent pool from." + } + }, + "enableAutoScaling": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable auto-scaling for the agent pool." + } + }, + "enableEncryptionAtHost": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable encryption at host for the agent pool." + } + }, + "enableFIPS": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable FIPS for the agent pool." + } + }, + "enableNodePublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable node public IP for the agent pool." + } + }, + "enableUltraSSD": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable Ultra SSD for the agent pool." + } + }, + "gpuInstanceProfile": { + "type": "string", + "allowedValues": [ + "MIG1g", + "MIG2g", + "MIG3g", + "MIG4g", + "MIG7g" + ], + "nullable": true, + "metadata": { + "description": "Optional. The GPU instance profile of the agent pool." + } + }, + "kubeletDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The kubelet disk type of the agent pool." + } + }, + "maxCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "minCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "maxPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of pods that can run on a node." + } + }, + "minPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of pods that can run on a node." + } + }, + "mode": { + "type": "string", + "allowedValues": [ + "System", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The mode of the agent pool." + } + }, + "nodeLabels": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The node labels of the agent pool." + } + }, + "nodePublicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The node public IP prefix ID of the agent pool." + } + }, + "nodeTaints": { + "type": "array", + "items": { + "type": "string" }, - "enableDefaultTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. The enable default telemetry of the agent pool." - } + "nullable": true, + "metadata": { + "description": "Optional. The node taints of the agent pool." + } + }, + "orchestratorVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Kubernetes version of the agent pool." + } + }, + "osDiskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk size in GB of the agent pool." + } + }, + "osDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk type of the agent pool." + } + }, + "osSku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS SKU of the agent pool." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "nullable": true, + "metadata": { + "description": "Optional. The OS type of the agent pool." + } + }, + "podSubnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The pod subnet ID of the agent pool." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The proximity placement group resource ID of the agent pool." + } + }, + "scaleDownMode": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale down mode of the agent pool." + } + }, + "scaleSetEvictionPolicy": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set eviction policy of the agent pool." + } + }, + "scaleSetPriority": { + "type": "string", + "allowedValues": [ + "Low", + "Regular", + "Spot" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set priority of the agent pool." + } + }, + "spotMaxPrice": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The spot max price of the agent pool." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the agent pool." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "AvailabilitySet", + "VirtualMachineScaleSets" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the agent pool." + } + }, + "maxSurge": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of nodes that can be created during an upgrade." + } + }, + "vmSize": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VM size of the agent pool." + } + }, + "vnetSubnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VNet subnet ID of the agent pool." + } + }, + "workloadRuntime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The workload runtime of the agent pool." + } + }, + "enableDefaultTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The enable default telemetry of the agent pool." } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } }, "managedIdentitiesType": { "type": "object", @@ -340,7 +338,9 @@ } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } }, "lockType": { "type": "object", @@ -365,7 +365,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "roleAssignmentType": { "type": "array", @@ -438,7 +441,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "diagnosticSettingType": { "type": "array", @@ -558,7 +564,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "fluxConfigurationProtectedSettingsType": { "type": "object", @@ -571,7 +580,9 @@ } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } }, "extensionType": { "type": "object", @@ -633,7 +644,9 @@ } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } }, "customerManagedKeyType": { "type": "object", @@ -668,32 +681,33 @@ } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } }, "maintenanceConfigurationType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "allowedValues": [ - "aksManagedAutoUpgradeSchedule", - "aksManagedNodeOSUpgradeSchedule" - ], - "metadata": { - "description": "Required. Name of maintenance window." - } - }, - "maintenanceWindow": { - "type": "object", - "metadata": { - "description": "Required. Maintenance window for the maintenance configuration." - } + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "aksManagedAutoUpgradeSchedule", + "aksManagedNodeOSUpgradeSchedule" + ], + "metadata": { + "description": "Required. Name of maintenance window." + } + }, + "maintenanceWindow": { + "type": "object", + "metadata": { + "description": "Required. Maintenance window for the maintenance configuration." } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } } }, "parameters": { @@ -719,6 +733,7 @@ }, "managedIdentities": { "$ref": "#/definitions/managedIdentitiesType", + "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." } @@ -899,6 +914,9 @@ }, "aadProfileAdminGroupObjectIDs": { "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { "description": "Optional. Specifies the AAD group object IDs that will have admin role of the cluster." @@ -927,7 +945,7 @@ }, "disableLocalAccounts": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. If set to true, getting static credentials will be disabled for this cluster. This must only be used on Managed Clusters that are AAD enabled." } @@ -941,6 +959,9 @@ }, "authorizedIPRanges": { "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { "description": "Optional. IP ranges are specified in CIDR format, e.g. 137.117.106.88/29. This feature is not compatible with clusters that use Public IP Per Node, or clusters that are using a Basic Load Balancer." @@ -986,22 +1007,33 @@ "description": "Optional. Private DNS Zone configuration. Set to 'system' and AKS will create a private DNS zone in the node resource group. Set to '' to disable private DNS Zone creation and use public DNS. Supply the resource ID here of an existing Private DNS zone to use an existing zone." } }, - "primaryAgentPoolProfile": { + "primaryAgentPoolProfiles": { "type": "array", + "items": { + "$ref": "#/definitions/agentPoolType" + }, "metadata": { "description": "Required. Properties of the primary agent pool." } }, "agentPools": { - "$ref": "#/definitions/agentPoolType", + "type": "array", + "items": { + "$ref": "#/definitions/agentPoolType" + }, + "nullable": true, "metadata": { "description": "Optional. Define one or more secondary/additional agent pools." } }, "maintenanceConfigurations": { - "$ref": "#/definitions/maintenanceConfigurationType", + "type": "array", + "items": { + "$ref": "#/definitions/maintenanceConfigurationType" + }, + "nullable": true, "metadata": { - "description": "Optional. Maintenance Window for Cluster auto upgrade and node OS upgrade." + "description": "Optional. Whether or not to use AKS Automatic mode." } }, "costAnalysisEnabled": { @@ -1152,8 +1184,8 @@ } }, "autoScalerProfileMaxGracefulTerminationSec": { - "type": "string", - "defaultValue": "600", + "type": "int", + "defaultValue": 600, "metadata": { "description": "Optional. Specifies the max graceful termination time interval in seconds for the auto-scaler of the AKS cluster." } @@ -1179,8 +1211,8 @@ } }, "autoScalerProfileMaxEmptyBulkDelete": { - "type": "string", - "defaultValue": "10", + "type": "int", + "defaultValue": 10, "metadata": { "description": "Optional. Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster." } @@ -1193,8 +1225,8 @@ } }, "autoScalerProfileMaxTotalUnreadyPercentage": { - "type": "string", - "defaultValue": "45", + "type": "int", + "defaultValue": 45, "metadata": { "description": "Optional. Specifies the mximum total unready percentage for the auto-scaler of the AKS cluster. The maximum is 100 and the minimum is 0." } @@ -1207,8 +1239,8 @@ } }, "autoScalerProfileOkTotalUnreadyCount": { - "type": "string", - "defaultValue": "3", + "type": "int", + "defaultValue": 3, "metadata": { "description": "Optional. Specifies the OK total unready count for the auto-scaler of the AKS cluster." } @@ -1377,7 +1409,7 @@ "description": "Optional. Specifies whether the OMS agent is enabled." } }, - "monitoringWorkspaceId": { + "monitoringWorkspaceResourceId": { "type": "string", "nullable": true, "metadata": { @@ -1419,6 +1451,7 @@ }, "fluxExtension": { "$ref": "#/definitions/extensionType", + "nullable": true, "metadata": { "description": "Optional. Settings and configurations for the flux extension." } @@ -1453,6 +1486,7 @@ }, "customerManagedKey": { "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, "metadata": { "description": "Optional. The customer managed key definition." } @@ -1593,12 +1627,12 @@ "tier": "[parameters('skuTier')]" }, "properties": { + "agentPoolProfiles": "[map(parameters('primaryAgentPoolProfiles'), lambda('profile', createObject('name', lambdaVariables('profile').name, 'count', coalesce(lambdaVariables('profile').count, 1), 'availabilityZones', map(coalesce(tryGet(lambdaVariables('profile'), 'availabilityZones'), createArray(1, 2, 3)), lambda('zone', format('{0}', lambdaVariables('zone')))), 'creationData', if(not(empty(tryGet(lambdaVariables('profile'), 'sourceResourceId'))), createObject('sourceResourceId', lambdaVariables('profile').sourceResourceId), null()), 'enableAutoScaling', coalesce(tryGet(lambdaVariables('profile'), 'enableAutoScaling'), false()), 'enableEncryptionAtHost', coalesce(tryGet(lambdaVariables('profile'), 'enableEncryptionAtHost'), false()), 'enableFIPS', coalesce(tryGet(lambdaVariables('profile'), 'enableFIPS'), false()), 'enableNodePublicIP', coalesce(tryGet(lambdaVariables('profile'), 'enableNodePublicIP'), false()), 'enableUltraSSD', coalesce(tryGet(lambdaVariables('profile'), 'enableUltraSSD'), false()), 'gpuInstanceProfile', tryGet(lambdaVariables('profile'), 'gpuInstanceProfile'), 'kubeletDiskType', tryGet(lambdaVariables('profile'), 'kubeletDiskType'), 'maxCount', tryGet(lambdaVariables('profile'), 'maxCount'), 'maxPods', tryGet(lambdaVariables('profile'), 'maxPods'), 'minCount', tryGet(lambdaVariables('profile'), 'minCount'), 'mode', tryGet(lambdaVariables('profile'), 'mode'), 'nodeLabels', tryGet(lambdaVariables('profile'), 'nodeLabels'), 'nodePublicIPPrefixID', tryGet(lambdaVariables('profile'), 'nodePublicIpPrefixResourceId'), 'nodeTaints', tryGet(lambdaVariables('profile'), 'nodeTaints'), 'orchestratorVersion', tryGet(lambdaVariables('profile'), 'orchestratorVersion'), 'osDiskSizeGB', tryGet(lambdaVariables('profile'), 'osDiskSizeGB'), 'osDiskType', tryGet(lambdaVariables('profile'), 'osDiskType'), 'osType', coalesce(tryGet(lambdaVariables('profile'), 'osType'), 'Linux'), 'podSubnetID', tryGet(lambdaVariables('profile'), 'podSubnetResourceId'), 'proximityPlacementGroupID', tryGet(lambdaVariables('profile'), 'proximityPlacementGroupResourceId'), 'scaleDownMode', coalesce(tryGet(lambdaVariables('profile'), 'scaleDownMode'), 'Delete'), 'scaleSetEvictionPolicy', coalesce(tryGet(lambdaVariables('profile'), 'scaleSetEvictionPolicy'), 'Delete'), 'scaleSetPriority', tryGet(lambdaVariables('profile'), 'scaleSetPriority'), 'spotMaxPrice', tryGet(lambdaVariables('profile'), 'spotMaxPrice'), 'tags', tryGet(lambdaVariables('profile'), 'tags'), 'type', tryGet(lambdaVariables('profile'), 'type'), 'upgradeSettings', createObject('maxSurge', tryGet(lambdaVariables('profile'), 'maxSurge')), 'vmSize', coalesce(tryGet(lambdaVariables('profile'), 'vmSize'), 'Standard_D2s_v3'), 'vnetSubnetID', tryGet(lambdaVariables('profile'), 'vnetSubnetResourceId'), 'workloadRuntime', tryGet(lambdaVariables('profile'), 'workloadRuntime'))))]", "httpProxyConfig": "[parameters('httpProxyConfig')]", "identityProfile": "[parameters('identityProfile')]", "diskEncryptionSetID": "[parameters('diskEncryptionSetResourceId')]", "kubernetesVersion": "[parameters('kubernetesVersion')]", "dnsPrefix": "[parameters('dnsPrefix')]", - "agentPoolProfiles": "[parameters('primaryAgentPoolProfile')]", "linuxProfile": "[if(not(empty(parameters('sshPublicKey'))), createObject('adminUsername', parameters('adminUsername'), 'ssh', createObject('publicKeys', createArray(createObject('keyData', coalesce(parameters('sshPublicKey'), ''))))), null())]", "servicePrincipalProfile": "[parameters('aksServicePrincipalProfile')]", "metricsProfile": { @@ -1621,8 +1655,8 @@ "config": "[if(and(parameters('ingressApplicationGatewayEnabled'), not(empty(parameters('appGatewayResourceId')))), createObject('applicationGatewayId', parameters('appGatewayResourceId'), 'effectiveApplicationGatewayId', parameters('appGatewayResourceId')), null())]" }, "omsagent": { - "enabled": "[and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceId'))))]", - "config": "[if(and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceId')))), createObject('logAnalyticsWorkspaceResourceID', parameters('monitoringWorkspaceId')), null())]" + "enabled": "[and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceResourceId'))))]", + "config": "[if(and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceResourceId')))), createObject('logAnalyticsWorkspaceResourceID', parameters('monitoringWorkspaceResourceId')), null())]" }, "aciConnectorLinux": { "enabled": "[parameters('aciConnectorLinuxEnabled')]" @@ -1685,12 +1719,12 @@ "autoScalerProfile": { "balance-similar-node-groups": "[toLower(string(parameters('autoScalerProfileBalanceSimilarNodeGroups')))]", "expander": "[parameters('autoScalerProfileExpander')]", - "max-empty-bulk-delete": "[parameters('autoScalerProfileMaxEmptyBulkDelete')]", - "max-graceful-termination-sec": "[parameters('autoScalerProfileMaxGracefulTerminationSec')]", + "max-empty-bulk-delete": "[format('{0}', parameters('autoScalerProfileMaxEmptyBulkDelete'))]", + "max-graceful-termination-sec": "[format('{0}', parameters('autoScalerProfileMaxGracefulTerminationSec'))]", "max-node-provision-time": "[parameters('autoScalerProfileMaxNodeProvisionTime')]", - "max-total-unready-percentage": "[parameters('autoScalerProfileMaxTotalUnreadyPercentage')]", + "max-total-unready-percentage": "[format('{0}', parameters('autoScalerProfileMaxTotalUnreadyPercentage'))]", "new-pod-scale-up-delay": "[parameters('autoScalerProfileNewPodScaleUpDelay')]", - "ok-total-unready-count": "[parameters('autoScalerProfileOkTotalUnreadyCount')]", + "ok-total-unready-count": "[format('{0}', parameters('autoScalerProfileOkTotalUnreadyCount'))]", "scale-down-delay-after-add": "[parameters('autoScalerProfileScaleDownDelayAfterAdd')]", "scale-down-delay-after-delete": "[parameters('autoScalerProfileScaleDownDelayAfterDelete')]", "scale-down-delay-after-failure": "[parameters('autoScalerProfileScaleDownDelayAfterFailure')]", @@ -1713,7 +1747,7 @@ "privateDNSZone": "[parameters('privateDNSZone')]" }, "azureMonitorProfile": { - "containerInsights": "[if(parameters('enableContainerInsights'), createObject('enabled', parameters('enableContainerInsights'), 'logAnalyticsWorkspaceResourceId', if(not(empty(parameters('monitoringWorkspaceId'))), parameters('monitoringWorkspaceId'), null()), 'disableCustomMetrics', parameters('disableCustomMetrics'), 'disablePrometheusMetricsScraping', parameters('disablePrometheusMetricsScraping'), 'syslogPort', parameters('syslogPort')), null())]", + "containerInsights": "[if(parameters('enableContainerInsights'), createObject('enabled', parameters('enableContainerInsights'), 'logAnalyticsWorkspaceResourceId', if(not(empty(parameters('monitoringWorkspaceResourceId'))), parameters('monitoringWorkspaceResourceId'), null()), 'disableCustomMetrics', parameters('disableCustomMetrics'), 'disablePrometheusMetricsScraping', parameters('disablePrometheusMetricsScraping'), 'syslogPort', parameters('syslogPort')), null())]", "metrics": "[if(parameters('enableAzureMonitorProfileMetrics'), createObject('enabled', parameters('enableAzureMonitorProfileMetrics'), 'kubeStateMetrics', createObject('metricLabelsAllowlist', parameters('metricLabelsAllowlist'), 'metricAnnotationsAllowList', parameters('metricAnnotationsAllowList'))), null())]" }, "podIdentityProfile": { @@ -1723,7 +1757,7 @@ "userAssignedIdentityExceptions": "[parameters('podIdentityProfileUserAssignedIdentityExceptions')]" }, "securityProfile": { - "defender": "[if(parameters('enableAzureDefender'), createObject('securityMonitoring', createObject('enabled', parameters('enableAzureDefender')), 'logAnalyticsWorkspaceResourceId', parameters('monitoringWorkspaceId')), null())]", + "defender": "[if(parameters('enableAzureDefender'), createObject('securityMonitoring', createObject('enabled', parameters('enableAzureDefender')), 'logAnalyticsWorkspaceResourceId', parameters('monitoringWorkspaceResourceId')), null())]", "workloadIdentity": "[if(parameters('enableWorkloadIdentity'), createObject('enabled', parameters('enableWorkloadIdentity')), null())]", "imageCleaner": "[if(parameters('enableImageCleaner'), createObject('enabled', parameters('enableImageCleaner'), 'intervalHours', parameters('imageCleanerIntervalHours')), null())]" }, @@ -1849,10 +1883,9 @@ "name": "managedCluster_maintenanceConfigurations", "count": "[length(coalesce(parameters('maintenanceConfigurations'), createArray()))]" }, - "condition": "[not(empty(coalesce(parameters('maintenanceConfigurations'), createArray())[copyIndex()]))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-ManagedCluster-MaintenanceConfigurations-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-ManagedCluster-MaintenanceConfiguration-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -2007,8 +2040,8 @@ "nodeLabels": { "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodeLabels')]" }, - "nodePublicIpPrefixId": { - "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodePublicIpPrefixId')]" + "nodePublicIpPrefixResourceId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodePublicIpPrefixResourceId')]" }, "nodeTaints": { "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodeTaints')]" @@ -2028,8 +2061,8 @@ "osType": { "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osType')]" }, - "podSubnetId": { - "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'podSubnetId')]" + "podSubnetResourceId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'podSubnetResourceId')]" }, "proximityPlacementGroupResourceId": { "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'proximityPlacementGroupResourceId')]" @@ -2058,8 +2091,8 @@ "vmSize": { "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'vmSize')]" }, - "vnetSubnetId": { - "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'vnetSubnetId')]" + "vnetSubnetResourceId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'vnetSubnetResourceId')]" }, "workloadRuntime": { "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'workloadRuntime')]" @@ -2073,7 +2106,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "4315564225725874539" + "templateHash": "13856766172443517827" }, "name": "Azure Kubernetes Service (AKS) Managed Cluster Agent Pools", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Agent Pool.", @@ -2094,7 +2127,14 @@ }, "availabilityZones": { "type": "array", - "nullable": true, + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], "metadata": { "description": "Optional. The list of Availability zones to use for nodes. This can only be specified if the AgentPoolType property is \"VirtualMachineScaleSets\"." } @@ -2206,7 +2246,7 @@ "description": "Optional. The node labels to be persisted across all nodes in agent pool." } }, - "nodePublicIpPrefixId": { + "nodePublicIpPrefixResourceId": { "type": "string", "nullable": true, "metadata": { @@ -2270,11 +2310,11 @@ "description": "Optional. The operating system type. The default is Linux." } }, - "podSubnetId": { + "podSubnetResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Subnet ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." + "description": "Optional. Subnet resource ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." } }, "proximityPlacementGroupResourceId": { @@ -2352,7 +2392,7 @@ "description": "Optional. VM size. VM size availability varies by region. If a node contains insufficient compute resources (memory, cpu, etc) pods might fail to run correctly. For more details on restricted VM sizes, see: /azure/aks/quotas-skus-regions." } }, - "vnetSubnetId": { + "vnetSubnetResourceId": { "type": "string", "nullable": true, "metadata": { @@ -2379,7 +2419,7 @@ "apiVersion": "2023-07-02-preview", "name": "[format('{0}/{1}', parameters('managedClusterName'), parameters('name'))]", "properties": { - "availabilityZones": "[parameters('availabilityZones')]", + "availabilityZones": "[map(coalesce(parameters('availabilityZones'), createArray()), lambda('zone', format('{0}', lambdaVariables('zone'))))]", "count": "[parameters('count')]", "creationData": "[if(not(empty(parameters('sourceResourceId'))), createObject('sourceResourceId', parameters('sourceResourceId')), null())]", "enableAutoScaling": "[parameters('enableAutoScaling')]", @@ -2394,14 +2434,14 @@ "minCount": "[parameters('minCount')]", "mode": "[parameters('mode')]", "nodeLabels": "[parameters('nodeLabels')]", - "nodePublicIPPrefixID": "[parameters('nodePublicIpPrefixId')]", + "nodePublicIPPrefixID": "[parameters('nodePublicIpPrefixResourceId')]", "nodeTaints": "[parameters('nodeTaints')]", "orchestratorVersion": "[parameters('orchestratorVersion')]", "osDiskSizeGB": "[parameters('osDiskSizeGB')]", "osDiskType": "[parameters('osDiskType')]", "osSKU": "[parameters('osSku')]", "osType": "[parameters('osType')]", - "podSubnetID": "[parameters('podSubnetId')]", + "podSubnetID": "[parameters('podSubnetResourceId')]", "proximityPlacementGroupID": "[parameters('proximityPlacementGroupResourceId')]", "scaleDownMode": "[parameters('scaleDownMode')]", "scaleSetEvictionPolicy": "[parameters('scaleSetEvictionPolicy')]", @@ -2413,7 +2453,7 @@ "maxSurge": "[parameters('maxSurge')]" }, "vmSize": "[parameters('vmSize')]", - "vnetSubnetID": "[parameters('vnetSubnetId')]", + "vnetSubnetID": "[parameters('vnetSubnetResourceId')]", "workloadRuntime": "[parameters('workloadRuntime')]" }, "dependsOn": [ diff --git a/avm/res/container-service/managed-cluster/maintenance-configurations/main.json b/avm/res/container-service/managed-cluster/maintenance-configurations/main.json index 3c4f84d104..22e9300b85 100644 --- a/avm/res/container-service/managed-cluster/maintenance-configurations/main.json +++ b/avm/res/container-service/managed-cluster/maintenance-configurations/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12168542117744033419" + "version": "0.30.23.60470", + "templateHash": "2505380725266419010" }, "name": "Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations", "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations.", diff --git a/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep index cd20ff76e7..7852289f4c 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/automatic/main.test.bicep @@ -62,8 +62,7 @@ module testDeployment '../../../main.bicep' = [ managedIdentities: { systemAssigned: true } - - primaryAgentPoolProfile: [ + primaryAgentPoolProfiles: [ { name: 'systempool' count: 3 diff --git a/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep index 76e6c50044..d21dfdcb2d 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/azure/main.test.bicep @@ -76,10 +76,10 @@ module testDeployment '../../../main.bicep' = [ params: { location: resourceLocation name: '${namePrefix}${serviceShort}001' - primaryAgentPoolProfile: [ + primaryAgentPoolProfiles: [ { availabilityZones: [ - '3' + 3 ] count: 1 enableAutoScaling: true @@ -95,13 +95,13 @@ module testDeployment '../../../main.bicep' = [ osType: 'Linux' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: nestedDependencies.outputs.subnetResourceIds[0] + vnetSubnetResourceId: nestedDependencies.outputs.subnetResourceIds[0] } ] agentPools: [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -118,12 +118,12 @@ module testDeployment '../../../main.bicep' = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: nestedDependencies.outputs.subnetResourceIds[1] + vnetSubnetResourceId: nestedDependencies.outputs.subnetResourceIds[1] proximityPlacementGroupResourceId: nestedDependencies.outputs.proximityPlacementGroupResourceId } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -140,7 +140,7 @@ module testDeployment '../../../main.bicep' = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: nestedDependencies.outputs.subnetResourceIds[2] + vnetSubnetResourceId: nestedDependencies.outputs.subnetResourceIds[2] } ] autoUpgradeProfileUpgradeChannel: 'stable' @@ -213,7 +213,7 @@ module testDeployment '../../../main.bicep' = [ } } omsAgentEnabled: true - monitoringWorkspaceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + monitoringWorkspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId enableAzureDefender: true enableKeyvaultSecretsProvider: true enablePodSecurityPolicy: false diff --git a/avm/res/container-service/managed-cluster/tests/e2e/defaults/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/defaults/main.test.bicep index 60a4103ddd..48b0faca8c 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/defaults/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/defaults/main.test.bicep @@ -42,7 +42,7 @@ module testDeployment '../../../main.bicep' = [ managedIdentities: { systemAssigned: true } - primaryAgentPoolProfile: [ + primaryAgentPoolProfiles: [ { name: 'systempool' count: 3 diff --git a/avm/res/container-service/managed-cluster/tests/e2e/kubenet/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/kubenet/main.test.bicep index 6b5171e708..03235dc22b 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/kubenet/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/kubenet/main.test.bicep @@ -67,10 +67,10 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: resourceLocation - primaryAgentPoolProfile: [ + primaryAgentPoolProfiles: [ { availabilityZones: [ - '3' + 3 ] count: 1 enableAutoScaling: true @@ -91,7 +91,7 @@ module testDeployment '../../../main.bicep' = [ agentPools: [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -111,7 +111,7 @@ module testDeployment '../../../main.bicep' = [ } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true diff --git a/avm/res/container-service/managed-cluster/tests/e2e/priv/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/priv/main.test.bicep index 94bf2b0d23..555258a93b 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/priv/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/priv/main.test.bicep @@ -55,10 +55,10 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: resourceLocation enablePrivateCluster: true - primaryAgentPoolProfile: [ + primaryAgentPoolProfiles: [ { availabilityZones: [ - '3' + 3 ] count: 1 enableAutoScaling: true @@ -74,13 +74,13 @@ module testDeployment '../../../main.bicep' = [ osType: 'Linux' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' + vnetSubnetResourceId: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' } ] agentPools: [ { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true @@ -97,11 +97,11 @@ module testDeployment '../../../main.bicep' = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' + vnetSubnetResourceId: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' } { availabilityZones: [ - '3' + 3 ] count: 2 enableAutoScaling: true diff --git a/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep b/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep index bb0487a6a1..4b88dc1c87 100644 --- a/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/container-service/managed-cluster/tests/e2e/waf-aligned/main.test.bicep @@ -71,10 +71,10 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: resourceLocation enablePrivateCluster: true - primaryAgentPoolProfile: [ + primaryAgentPoolProfiles: [ { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -90,13 +90,13 @@ module testDeployment '../../../main.bicep' = [ osType: 'Linux' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' + vnetSubnetResourceId: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' } ] agentPools: [ { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -114,11 +114,11 @@ module testDeployment '../../../main.bicep' = [ scaleSetPriority: 'Regular' type: 'VirtualMachineScaleSets' vmSize: 'Standard_DS2_v2' - vnetSubnetID: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' + vnetSubnetResourceId: '${nestedDependencies.outputs.vNetResourceId}/subnets/defaultSubnet' } { availabilityZones: [ - '3' + 3 ] count: 3 enableAutoScaling: true @@ -178,7 +178,7 @@ module testDeployment '../../../main.bicep' = [ dnsServiceIP: '10.10.200.10' serviceCidr: '10.10.200.0/24' omsAgentEnabled: true - monitoringWorkspaceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + monitoringWorkspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId disableLocalAccounts: true enableAzureDefender: true diagnosticSettings: [ From 11fce9316972e355a760456404d33bd7edf41e7c Mon Sep 17 00:00:00 2001 From: Buddy <38195643+tsc-buddy@users.noreply.github.com> Date: Tue, 15 Oct 2024 00:31:27 +1300 Subject: [PATCH 78/93] feat: ACR Availability Zone Spec. (#3548) ## Description This PR contains the changes to deploy ACR as zone redundant by default to meeting AVM specs. ## Pipeline Reference | Pipeline | | -------- | |[![avm.res.container-registry.registry](https://github.com/tsc-buddy/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml/badge.svg)](https://github.com/tsc-buddy/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml)| ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/container-registry/registry/README.md | 4 +-- .../registry/cache-rule/main.json | 4 +-- .../registry/credential-set/main.json | 4 +-- .../container-registry/registry/main.bicep | 4 +-- avm/res/container-registry/registry/main.json | 28 +++++++++---------- .../registry/replication/main.json | 4 +-- .../registry/scope-map/main.json | 4 +-- .../container-registry/registry/version.json | 2 +- .../registry/webhook/main.json | 4 +-- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/avm/res/container-registry/registry/README.md b/avm/res/container-registry/registry/README.md index eb764f51d8..4be75ae21b 100644 --- a/avm/res/container-registry/registry/README.md +++ b/avm/res/container-registry/registry/README.md @@ -1138,7 +1138,7 @@ Tier of your Azure container registry. - Required: No - Type: string -- Default: `'Basic'` +- Default: `'Premium'` - Allowed: ```Bicep [ @@ -2194,7 +2194,7 @@ Whether or not zone redundancy is enabled for this container registry. - Required: No - Type: string -- Default: `'Disabled'` +- Default: `'Enabled'` - Allowed: ```Bicep [ diff --git a/avm/res/container-registry/registry/cache-rule/main.json b/avm/res/container-registry/registry/cache-rule/main.json index 3536c9537a..4635d8cb66 100644 --- a/avm/res/container-registry/registry/cache-rule/main.json +++ b/avm/res/container-registry/registry/cache-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14369419482171687857" + "version": "0.30.3.12046", + "templateHash": "17205938486061573561" }, "name": "Container Registries Cache", "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", diff --git a/avm/res/container-registry/registry/credential-set/main.json b/avm/res/container-registry/registry/credential-set/main.json index 381d007948..1b1f243390 100644 --- a/avm/res/container-registry/registry/credential-set/main.json +++ b/avm/res/container-registry/registry/credential-set/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12196074162662855376" + "version": "0.30.3.12046", + "templateHash": "13281764602355848660" }, "name": "Container Registries Credential Sets", "description": "This module deploys an ACR Credential Set.", diff --git a/avm/res/container-registry/registry/main.bicep b/avm/res/container-registry/registry/main.bicep index cb3cbc79b2..e164a1be14 100644 --- a/avm/res/container-registry/registry/main.bicep +++ b/avm/res/container-registry/registry/main.bicep @@ -22,7 +22,7 @@ param roleAssignments roleAssignmentType 'Premium' 'Standard' ]) -param acrSku string = 'Basic' +param acrSku string = 'Premium' @allowed([ 'disabled' @@ -107,7 +107,7 @@ param privateEndpoints privateEndpointType 'Enabled' ]) @description('Optional. Whether or not zone redundancy is enabled for this container registry.') -param zoneRedundancy string = 'Disabled' +param zoneRedundancy string = 'Enabled' @description('Optional. All replications to create.') param replications array? diff --git a/avm/res/container-registry/registry/main.json b/avm/res/container-registry/registry/main.json index bc420f1e32..a54cb59fe1 100644 --- a/avm/res/container-registry/registry/main.json +++ b/avm/res/container-registry/registry/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2885305905621743300" + "version": "0.30.3.12046", + "templateHash": "14769734612544320664" }, "name": "Azure Container Registries (ACR)", "description": "This module deploys an Azure Container Registry (ACR).", @@ -570,7 +570,7 @@ }, "acrSku": { "type": "string", - "defaultValue": "Basic", + "defaultValue": "Premium", "allowedValues": [ "Basic", "Premium", @@ -715,7 +715,7 @@ }, "zoneRedundancy": { "type": "string", - "defaultValue": "Disabled", + "defaultValue": "Enabled", "allowedValues": [ "Disabled", "Enabled" @@ -1028,8 +1028,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9144531012597082524" + "version": "0.30.3.12046", + "templateHash": "17045733538280748766" }, "name": "Container Registries scopeMaps", "description": "This module deploys an Azure Container Registry (ACR) scopeMap.", @@ -1155,8 +1155,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8531695368487734118" + "version": "0.30.3.12046", + "templateHash": "11507205381257602922" }, "name": "Azure Container Registry (ACR) Replications", "description": "This module deploys an Azure Container Registry (ACR) Replication.", @@ -1303,8 +1303,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12196074162662855376" + "version": "0.30.3.12046", + "templateHash": "13281764602355848660" }, "name": "Container Registries Credential Sets", "description": "This module deploys an ACR Credential Set.", @@ -1478,8 +1478,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14369419482171687857" + "version": "0.30.3.12046", + "templateHash": "17205938486061573561" }, "name": "Container Registries Cache", "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", @@ -1610,8 +1610,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14912363209364245195" + "version": "0.30.3.12046", + "templateHash": "3542060088842117365" }, "name": "Azure Container Registry (ACR) Webhooks", "description": "This module deploys an Azure Container Registry (ACR) Webhook.", diff --git a/avm/res/container-registry/registry/replication/main.json b/avm/res/container-registry/registry/replication/main.json index d6315f34c4..beca1e3cec 100644 --- a/avm/res/container-registry/registry/replication/main.json +++ b/avm/res/container-registry/registry/replication/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8531695368487734118" + "version": "0.30.3.12046", + "templateHash": "11507205381257602922" }, "name": "Azure Container Registry (ACR) Replications", "description": "This module deploys an Azure Container Registry (ACR) Replication.", diff --git a/avm/res/container-registry/registry/scope-map/main.json b/avm/res/container-registry/registry/scope-map/main.json index bd25f89561..c19212c9a3 100644 --- a/avm/res/container-registry/registry/scope-map/main.json +++ b/avm/res/container-registry/registry/scope-map/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9144531012597082524" + "version": "0.30.3.12046", + "templateHash": "17045733538280748766" }, "name": "Container Registries scopeMaps", "description": "This module deploys an Azure Container Registry (ACR) scopeMap.", diff --git a/avm/res/container-registry/registry/version.json b/avm/res/container-registry/registry/version.json index a8eda31021..e42c3d9e5f 100644 --- a/avm/res/container-registry/registry/version.json +++ b/avm/res/container-registry/registry/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.5", + "version": "0.6", "pathFilters": [ "./main.json" ] diff --git a/avm/res/container-registry/registry/webhook/main.json b/avm/res/container-registry/registry/webhook/main.json index 66adb6a4cf..d5805e9f69 100644 --- a/avm/res/container-registry/registry/webhook/main.json +++ b/avm/res/container-registry/registry/webhook/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14912363209364245195" + "version": "0.30.3.12046", + "templateHash": "3542060088842117365" }, "name": "Azure Container Registry (ACR) Webhooks", "description": "This module deploys an Azure Container Registry (ACR) Webhook.", From cab8eda1a15aa96cce930448a5fd2547197dc07d Mon Sep 17 00:00:00 2001 From: hundredacres Date: Mon, 14 Oct 2024 06:34:36 -0700 Subject: [PATCH 79/93] fix: Add support for CI secret (#3507) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Added CI secret and updated tests. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.fabric.capacity](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.fabric.capacity.yml/badge.svg?branch=fix%2Fissues%2Ffabric_admin)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.fabric.capacity.yml) | ## Type of Change - [X] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/res/fabric/capacity/README.md | 16 ++++++++-------- avm/res/fabric/capacity/main.bicep | 2 +- avm/res/fabric/capacity/main.json | 2 +- .../capacity/tests/e2e/defaults/main.test.bicep | 7 ++++++- .../tests/e2e/waf-aligned/main.test.bicep | 6 +++++- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/avm/res/fabric/capacity/README.md b/avm/res/fabric/capacity/README.md index 8cec8824cb..d8f391e37b 100644 --- a/avm/res/fabric/capacity/README.md +++ b/avm/res/fabric/capacity/README.md @@ -42,7 +42,7 @@ module capacity 'br/public:avm/res/fabric/capacity:' = { params: { // Required parameters adminMembers: [ - 'mattschmitt@microsoft.com' + '' ] name: 'fcmin001' // Non-required parameters @@ -66,7 +66,7 @@ module capacity 'br/public:avm/res/fabric/capacity:' = { // Required parameters "adminMembers": { "value": [ - "mattschmitt@microsoft.com" + "" ] }, "name": { @@ -92,7 +92,7 @@ using 'br/public:avm/res/fabric/capacity:' // Required parameters param adminMembers = [ - 'mattschmitt@microsoft.com' + '' ] param name = 'fcmin001' // Non-required parameters @@ -117,7 +117,7 @@ module capacity 'br/public:avm/res/fabric/capacity:' = { params: { // Required parameters adminMembers: [ - 'mattschmitt@microsoft.com' + '' ] name: 'fcwaf001' // Non-required parameters @@ -142,7 +142,7 @@ module capacity 'br/public:avm/res/fabric/capacity:' = { // Required parameters "adminMembers": { "value": [ - "mattschmitt@microsoft.com" + "" ] }, "name": { @@ -171,7 +171,7 @@ using 'br/public:avm/res/fabric/capacity:' // Required parameters param adminMembers = [ - 'mattschmitt@microsoft.com' + '' ] param name = 'fcwaf001' // Non-required parameters @@ -196,7 +196,7 @@ param skuName = 'F64' | Parameter | Type | Description | | :-- | :-- | :-- | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | -| [`location`](#parameter-location) | string | Location for all Resources. | +| [`location`](#parameter-location) | string | Location for all resources. | | [`skuName`](#parameter-skuname) | string | SKU tier of the Fabric resource. | | [`skuTier`](#parameter-skutier) | string | SKU name of the Fabric resource. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -225,7 +225,7 @@ Enable/Disable usage telemetry for module. ### Parameter: `location` -Location for all Resources. +Location for all resources. - Required: No - Type: string diff --git a/avm/res/fabric/capacity/main.bicep b/avm/res/fabric/capacity/main.bicep index 3e855ad580..65c6a7242d 100644 --- a/avm/res/fabric/capacity/main.bicep +++ b/avm/res/fabric/capacity/main.bicep @@ -5,7 +5,7 @@ metadata owner = 'Azure/module-maintainers' @description('Required. Name of the resource to create.') param name string -@description('Optional. Location for all Resources.') +@description('Optional. Location for all resources.') param location string = resourceGroup().location @description('Optional. Tags of the resource.') diff --git a/avm/res/fabric/capacity/main.json b/avm/res/fabric/capacity/main.json index c6d0daee58..f90c00a5fc 100644 --- a/avm/res/fabric/capacity/main.json +++ b/avm/res/fabric/capacity/main.json @@ -23,7 +23,7 @@ "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Location for all resources." } }, "tags": { diff --git a/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep b/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep index a0057419f4..b285a9bae0 100644 --- a/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep +++ b/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep @@ -20,6 +20,11 @@ param serviceShort string = 'fcmin' @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_#' +@description('Required. Email address used by resource. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-adminMembersSecret\'.') +@secure() +param adminMembersSecret string = '' + + // ============ // // Dependencies // // ============ // @@ -44,7 +49,7 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: resourceLocation adminMembers: [ - 'mattschmitt@microsoft.com' + adminMembersSecret ] } } diff --git a/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep b/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep index 903ccd6b35..023b261784 100644 --- a/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep @@ -20,6 +20,10 @@ param serviceShort string = 'fcwaf' @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_#' +@description('Required. Email address used by resource. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-adminMembersSecret\'.') +@secure() +param adminMembersSecret string = '' + // ============ // // Dependencies // // ============ // @@ -45,7 +49,7 @@ module testDeployment '../../../main.bicep' = [ location: resourceLocation skuName: 'F64' adminMembers: [ - 'mattschmitt@microsoft.com' + adminMembersSecret ] } } From d484057b686b0c780a51cc1efc5a849c88518c4b Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 14 Oct 2024 18:34:59 +0200 Subject: [PATCH 80/93] fix: Trigger AZD AKS publishing (#3512) ## Description - Updates the API versions of referenced modules to trigger publishing Dependend on #3228 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.aks](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml/badge.svg?branch=users%2Falsehr%2FazdAKSPublishing&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/ptn/azd/aks/README.md | 19 +- avm/ptn/azd/aks/main.bicep | 4 +- avm/ptn/azd/aks/main.json | 578 +++++++++++++----- .../aks/tests/e2e/defaults/main.test.bicep | 1 + avm/ptn/azd/aks/tests/e2e/max/main.test.bicep | 21 +- 5 files changed, 458 insertions(+), 165 deletions(-) diff --git a/avm/ptn/azd/aks/README.md b/avm/ptn/azd/aks/README.md index 18098d7a71..6e87179a15 100644 --- a/avm/ptn/azd/aks/README.md +++ b/avm/ptn/azd/aks/README.md @@ -35,8 +35,8 @@ Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as we | `Microsoft.KeyVault/vaults/secrets` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/secrets) | | `Microsoft.KubernetesConfiguration/extensions` | [2022-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KubernetesConfiguration/2022-03-01/extensions) | | `Microsoft.KubernetesConfiguration/fluxConfigurations` | [2022-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KubernetesConfiguration/2022-03-01/fluxConfigurations) | -| `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | -| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `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 @@ -70,6 +70,7 @@ module aks 'br/public:avm/ptn/azd/aks:' = { principalId: '' // Non-required parameters location: '' + principalType: 'ServicePrincipal' } } ``` @@ -105,6 +106,9 @@ module aks 'br/public:avm/ptn/azd/aks:' = { // Non-required parameters "location": { "value": "" + }, + "principalType": { + "value": "ServicePrincipal" } } } @@ -128,6 +132,7 @@ param name = '' param principalId = '' // Non-required parameters param location = '' +param principalType = 'ServicePrincipal' ``` @@ -162,7 +167,7 @@ module aks 'br/public:avm/ptn/azd/aks:' = { name: 'npuserpool' osType: 'Linux' type: 'VirtualMachineScaleSets' - vmSize: 'standard_a2' + vmSize: 'standard_a2_v2' } ] aksClusterRoleAssignmentName: '' @@ -217,7 +222,7 @@ module aks 'br/public:avm/ptn/azd/aks:' = { "name": "npuserpool", "osType": "Linux", "type": "VirtualMachineScaleSets", - "vmSize": "standard_a2" + "vmSize": "standard_a2_v2" } ] }, @@ -272,7 +277,7 @@ param agentPools = [ name: 'npuserpool' osType: 'Linux' type: 'VirtualMachineScaleSets' - vmSize: 'standard_a2' + vmSize: 'standard_a2_v2' } ] param aksClusterRoleAssignmentName = '' @@ -1036,9 +1041,9 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/container-registry/registry:0.4.0` | Remote reference | +| `br/public:avm/res/container-registry/registry:0.5.1` | Remote reference | | `br/public:avm/res/container-service/managed-cluster:0.3.0` | Remote reference | -| `br/public:avm/res/key-vault/vault:0.7.1` | Remote reference | +| `br/public:avm/res/key-vault/vault:0.9.0` | Remote reference | ## Data Collection diff --git a/avm/ptn/azd/aks/main.bicep b/avm/ptn/azd/aks/main.bicep index 799530cbed..de942be0ab 100644 --- a/avm/ptn/azd/aks/main.bicep +++ b/avm/ptn/azd/aks/main.bicep @@ -255,7 +255,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:0.3.0 } } -module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = { +module containerRegistry 'br/public:avm/res/container-registry/registry:0.5.1' = { name: '${uniqueString(deployment().name, location)}-container-registry' params: { name: containerRegistryName @@ -296,7 +296,7 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = } } -module keyVault 'br/public:avm/res/key-vault/vault:0.7.1' = { +module keyVault 'br/public:avm/res/key-vault/vault:0.9.0' = { name: '${uniqueString(deployment().name, location)}-key-vault' params: { name: keyVaultName diff --git a/avm/ptn/azd/aks/main.json b/avm/ptn/azd/aks/main.json index ea34740356..6986a11e17 100644 --- a/avm/ptn/azd/aks/main.json +++ b/avm/ptn/azd/aks/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1486388262618258805" + "version": "0.30.23.60470", + "templateHash": "5631747890720204830" }, "name": "Azd AKS", "description": "Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -3827,7 +3827,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "8799580877381308457" + "templateHash": "2449684443141404366" }, "name": "Azure Container Registries (ACR)", "description": "This module deploys an Azure Container Registry (ACR).", @@ -3994,21 +3994,44 @@ "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" + "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 groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, "isManualConnection": { @@ -4622,7 +4645,7 @@ "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')]", + "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')]" } }, @@ -4643,7 +4666,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -5277,7 +5300,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "4294329625336671928" + "templateHash": "14369419482171687857" }, "name": "Container Registries Cache", "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", @@ -5294,7 +5317,7 @@ "type": "string", "defaultValue": "[replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-')]", "metadata": { - "description": "Optional. The name of the cache rule. Will be dereived from the source repository name if not defined." + "description": "Optional. The name of the cache rule. Will be derived from the source repository name if not defined." } }, "sourceRepository": { @@ -5604,11 +5627,8 @@ "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')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, "roleAssignments": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" @@ -5636,19 +5656,47 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" + "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": { @@ -5752,13 +5800,13 @@ "groupId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "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." + "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": { @@ -5792,8 +5840,11 @@ "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." + "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": { @@ -5833,8 +5884,11 @@ "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." + "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": { @@ -5882,6 +5936,29 @@ } }, "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": { @@ -5917,18 +5994,11 @@ "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", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "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 private DNS zone group to configure for the private endpoint." } }, "location": { @@ -5984,6 +6054,13 @@ } }, "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')]", @@ -6001,8 +6078,8 @@ "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))]", + "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": { @@ -6020,7 +6097,7 @@ }, "privateEndpoint": { "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", + "apiVersion": "2023-11-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -6061,27 +6138,27 @@ "privateEndpoint_roleAssignments": { "copy": { "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), 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)]", + "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": "[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')]" + "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('privateDnsZoneResourceIds')))]", + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", @@ -6092,28 +6169,52 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + "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.25.53.49325", - "templateHash": "11244630631275470040" + "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", @@ -6121,12 +6222,15 @@ "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "privateDNSResourceIds": { + "privateDnsZoneConfigs": { "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, "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." + "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": { @@ -6140,27 +6244,36 @@ "variables": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" } } } ] }, - "resources": [ - { + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", + "apiVersion": "2023-11-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] } - ], + }, "outputs": { "name": { "type": "string", @@ -6218,14 +6331,28 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + "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(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + "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), ''), ''))]" } } } @@ -6297,6 +6424,22 @@ "count": "[length(range(0, length(parameters('credentialSets'))))]", "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.resourceId.value]" } + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the Azure container registry." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('registry_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } } } } @@ -6344,7 +6487,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "6878673228466609441" + "templateHash": "10085839006881327962" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -6583,21 +6726,44 @@ "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" + "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 groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, "isManualConnection": { @@ -7387,7 +7553,7 @@ "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')]", + "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')]" } }, @@ -7396,7 +7562,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('0.9.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -7809,7 +7975,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "4990258423482296566" + "templateHash": "114626909766354577" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -7968,7 +8134,7 @@ "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')]", + "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')]" } }, @@ -8107,7 +8273,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "10436564794447478489" + "templateHash": "14269695922191217406" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -8317,7 +8483,7 @@ "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')]", + "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')]" } }, @@ -8434,11 +8600,8 @@ "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')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, "roleAssignments": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" @@ -8466,19 +8629,47 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" + "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": { @@ -8582,13 +8773,13 @@ "groupId": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "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." + "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": { @@ -8622,8 +8813,11 @@ "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." + "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": { @@ -8663,8 +8857,11 @@ "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." + "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": { @@ -8712,6 +8909,29 @@ } }, "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": { @@ -8747,18 +8967,11 @@ "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", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "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 private DNS zone group to configure for the private endpoint." } }, "location": { @@ -8814,6 +9027,13 @@ } }, "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')]", @@ -8831,8 +9051,8 @@ "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))]", + "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": { @@ -8850,7 +9070,7 @@ }, "privateEndpoint": { "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", + "apiVersion": "2023-11-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -8891,27 +9111,27 @@ "privateEndpoint_roleAssignments": { "copy": { "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), 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)]", + "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": "[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')]" + "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('privateDnsZoneResourceIds')))]", + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", @@ -8922,28 +9142,52 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + "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.25.53.49325", - "templateHash": "11244630631275470040" + "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", @@ -8951,12 +9195,15 @@ "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "privateDNSResourceIds": { + "privateDnsZoneConfigs": { "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, "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." + "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": { @@ -8970,27 +9217,36 @@ "variables": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" } } } ] }, - "resources": [ - { + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", + "apiVersion": "2023-11-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] } - ], + }, "outputs": { "name": { "type": "string", @@ -9048,14 +9304,28 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + "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(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + "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), ''), ''))]" } } } @@ -9100,6 +9370,22 @@ "description": "The location the resource was deployed into." }, "value": "[reference('keyVault', '2022-07-01', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the key vault." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(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": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } } } } diff --git a/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep index 0e40826546..0d0451cc8d 100644 --- a/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep +++ b/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep @@ -58,6 +58,7 @@ module testDeployment '../../../main.bicep' = [ keyVaultName: 'kv${uniqueString(deployment().name)}-${serviceShort}' location: resourceLocation principalId: nestedDependencies.outputs.identityPrincipalId + principalType: 'ServicePrincipal' } } ] diff --git a/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep b/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep index 964c796fff..cc61a356d6 100644 --- a/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep +++ b/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep @@ -11,9 +11,6 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-azd-aks-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'paamax' @@ -26,6 +23,10 @@ param containerRegistryRoleName string = newGuid() @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') param aksClusterRoleAssignmentName string = newGuid() +// Enforced location als not all regions have quota available +#disable-next-line no-hardcoded-location +var enforcedLocation = 'northeurope' + // ============ // // Dependencies // // ============ // @@ -34,14 +35,14 @@ param aksClusterRoleAssignmentName string = newGuid() // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { - name: '${uniqueString(deployment().name, resourceLocation)}-test-dependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-dependencies' scope: resourceGroup params: { - location: resourceLocation + location: enforcedLocation appName: 'dep-${namePrefix}-app-${serviceShort}' appServicePlanName: 'dep-${namePrefix}-apps-${serviceShort}' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' @@ -56,10 +57,10 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: 'mc${uniqueString(deployment().name)}-${serviceShort}' - containerRegistryName: '${uniqueString(deployment().name, resourceLocation)}testcontainerregistry${serviceShort}' + containerRegistryName: '${uniqueString(deployment().name, enforcedLocation)}testcontainerregistry${serviceShort}' skuTier: 'Free' webApplicationRoutingEnabled: true agentPools: [ @@ -70,12 +71,12 @@ module testDeployment '../../../main.bicep' = [ maxPods: 30 type: 'VirtualMachineScaleSets' maxSurge: '33%' - vmSize: 'standard_a2' + vmSize: 'standard_a2_v2' } ] logAnalyticsName: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId keyVaultName: 'kv${uniqueString(deployment().name)}-${serviceShort}' - location: resourceLocation + location: enforcedLocation principalId: nestedDependencies.outputs.identityPrincipalId acrSku: 'Basic' dnsPrefix: 'dep-${namePrefix}-dns-${serviceShort}' From 786994297c3d960d398aa307fafc0a686519a125 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 14 Oct 2024 19:03:51 +0200 Subject: [PATCH 81/93] fix: AZD ML Project - Adjusted KeyVault access policies deployment (#3553) ## Description - Fixed AZD ML Project access policies deployment to use native Bicep code. - Using the AVM module in this case is not a good idea as it sets several default values (such as purge protection) ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-project](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg?branch=users%2Falsehr%2FazdMLSoftDelete2&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/ptn/azd/ml-project/README.md | 6 +- avm/ptn/azd/ml-project/main.bicep | 23 +- avm/ptn/azd/ml-project/main.json | 2971 +---------------- .../tests/e2e/defaults/main.test.bicep | 2 +- 4 files changed, 37 insertions(+), 2965 deletions(-) diff --git a/avm/ptn/azd/ml-project/README.md b/avm/ptn/azd/ml-project/README.md index adc6341c6e..c4358560ac 100644 --- a/avm/ptn/azd/ml-project/README.md +++ b/avm/ptn/azd/ml-project/README.md @@ -20,10 +20,7 @@ Create a machine learning workspace, configure the key vault access policy and a | `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` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-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.KeyVault/vaults/accessPolicies` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/accessPolicies) | | `Microsoft.MachineLearningServices/workspaces` | [2024-04-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01-preview/workspaces) | | `Microsoft.MachineLearningServices/workspaces/computes` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2022-10-01/workspaces/computes) | | `Microsoft.MachineLearningServices/workspaces/connections` | [2024-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01/workspaces/connections) | @@ -324,7 +321,6 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/key-vault/vault:0.9.0` | Remote reference | | `br/public:avm/res/machine-learning-services/workspace:0.7.0` | Remote reference | | `br/public:avm/res/managed-identity/user-assigned-identity:0.4.0` | Remote reference | diff --git a/avm/ptn/azd/ml-project/main.bicep b/avm/ptn/azd/ml-project/main.bicep index 96179ddb4b..41a9b89c03 100644 --- a/avm/ptn/azd/ml-project/main.bicep +++ b/avm/ptn/azd/ml-project/main.bicep @@ -112,19 +112,18 @@ module project 'br/public:avm/res/machine-learning-services/workspace:0.7.0' = { resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { name: keyVaultName -} -module keyVaultAccess 'br/public:avm/res/key-vault/vault:0.9.0' = { - name: '${uniqueString(deployment().name, location)}-keyvault' - params: { - name: keyVault.name - accessPolicies: [ - { - objectId: project.outputs.systemAssignedMIPrincipalId - permissions: { secrets: ['get', 'list'] } - } - ] - enableTelemetry: enableTelemetry + resource keyVaultAccess 'accessPolicies@2023-07-01' = { + name: 'add' + properties: { + accessPolicies: [ + { + objectId: project.outputs.systemAssignedMIPrincipalId + permissions: { secrets: ['get', 'list'] } + tenantId: tenant().tenantId + } + ] + } } } diff --git a/avm/ptn/azd/ml-project/main.json b/avm/ptn/azd/ml-project/main.json index f130a38a14..a96f8c419f 100644 --- a/avm/ptn/azd/ml-project/main.json +++ b/avm/ptn/azd/ml-project/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "15406074241490987266" + "templateHash": "17417659473441028736" }, "name": "Azd Machine Learning workspace", "description": "Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -148,6 +148,29 @@ } }, "resources": { + "keyVault::keyVaultAccess": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference('project').outputs.systemAssignedMIPrincipalId.value]", + "permissions": { + "secrets": [ + "get", + "list" + ] + }, + "tenantId": "[tenant().tenantId]" + } + ] + }, + "dependsOn": [ + "keyVault", + "project" + ] + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", @@ -3979,2952 +4002,6 @@ } } }, - "keyVaultAccess": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('keyVaultName')]" - }, - "accessPolicies": { - "value": [ - { - "objectId": "[reference('project').outputs.systemAssignedMIPrincipalId.value]", - "permissions": { - "secrets": [ - "get", - "list" - ] - } - } - ] - }, - "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.29.47.4906", - "templateHash": "10085839006881327962" - }, - "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": { - "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": "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": "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('0.9.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" - } - } - } - } - }, - "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.29.47.4906", - "templateHash": "7494731697751039419" - }, - "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')]" - }, - "dependsOn": [ - "keyVault" - ] - } - }, - "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.29.47.4906", - "templateHash": "114626909766354577" - }, - "name": "Key Vault Secrets", - "description": "This module deploys a Key Vault Secret.", - "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 - } - }, - "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": { - "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')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "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'))]" - }, - "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.29.47.4906", - "templateHash": "14269695922191217406" - }, - "name": "Key Vault Keys", - "description": "This module deploys a Key Vault Key.", - "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 - } - }, - "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": { - "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": { - "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())]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "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": { - "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], '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": [ - "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", - "metadata": { - "description": "The private endpoints of the key vault." - }, - "copy": { - "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(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": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", - "customDnsConfig": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", - "networkInterfaceIds": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "keyVault", - "project" - ] - }, "mlServiceRoleAssigned": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", diff --git a/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep index 996d63a5bd..d60a1e0e8f 100644 --- a/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep +++ b/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep @@ -36,7 +36,7 @@ module dependencies 'dependencies.bicep' = { scope: resourceGroup params: { hubName: '${namePrefix}${serviceShort}hub001' - keyVaultName: '${namePrefix}${serviceShort}kv001' + keyVaultName: '${namePrefix}${serviceShort}kv002' storageAccountName: '${namePrefix}${serviceShort}sa001' } } From 7e97126655a9c341e033d82f9b0ae100b6184eb1 Mon Sep 17 00:00:00 2001 From: Don Heerschap Date: Mon, 14 Oct 2024 20:58:12 +0200 Subject: [PATCH 82/93] feat: `avm/res/db-for-postgre-sql/flexible-server` Add PEs in public mode (#2613) ## Description Adding possibility to deploy private endpoints when the server is in public mode. Closes [#2578](https://github.com/Azure/bicep-registry-modules/issues/2578) ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.db-for-postgre-sql.flexible-server](https://github.com/donheerschap/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=psqlPrivateEndpoint)](https://github.com/donheerschap/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Nate Arnold --- .../flexible-server/README.md | 550 ++++++++++- .../flexible-server/main.bicep | 136 ++- .../flexible-server/main.json | 888 +++++++++++++++++- .../e2e/public-with-pe/dependencies.bicep | 52 + .../tests/e2e/public-with-pe/main.test.bicep | 86 ++ .../tests/e2e/public/main.test.bicep | 8 +- .../flexible-server/version.json | 2 +- 7 files changed, 1697 insertions(+), 25 deletions(-) create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/dependencies.bicep create mode 100644 avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/main.test.bicep diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md index ec83051aaa..5eacd67679 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/README.md +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -8,6 +8,7 @@ This module deploys a DBforPostgreSQL Flexible Server. - [Usage examples](#Usage-examples) - [Parameters](#Parameters) - [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) - [Data Collection](#Data-Collection) ## Resource Types @@ -22,6 +23,8 @@ This module deploys a DBforPostgreSQL Flexible Server. | `Microsoft.DBforPostgreSQL/flexibleServers/databases` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/databases) | | `Microsoft.DBforPostgreSQL/flexibleServers/firewallRules` | [2022-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforPostgreSQL/2022-12-01/flexibleServers/firewallRules) | | `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-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | ## Usage examples @@ -34,8 +37,9 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using Customer-Managed-Keys with User-Assigned identity](#example-2-using-customer-managed-keys-with-user-assigned-identity) - [Private access](#example-3-private-access) -- [Public access](#example-4-public-access) -- [WAF-aligned](#example-5-waf-aligned) +- [Public access with private endpoints](#example-4-public-access-with-private-endpoints) +- [Public access](#example-5-public-access) +- [WAF-aligned](#example-6-waf-aligned) ### Example 1: _Using only defaults_ @@ -545,9 +549,9 @@ param tags = {

    -### Example 4: _Public access_ +### Example 4: _Public access with private endpoints_ -This instance deploys the module with public access. +This instance deploys the module with public access and private endpoints.

    @@ -559,7 +563,162 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + geoRedundantBackup: 'Enabled' + highAvailability: 'ZoneRedundant' + location: '' + maintenanceWindow: { + customWindow: 'Enabled' + dayOfWeek: '0' + startHour: '1' + startMinute: '0' + } + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + 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": "dfpsfspe001" + }, + "skuName": { + "value": "Standard_D2ds_v5" + }, + "tier": { + "value": "GeneralPurpose" + }, + // Non-required parameters + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "geoRedundantBackup": { + "value": "Enabled" + }, + "highAvailability": { + "value": "ZoneRedundant" + }, + "location": { + "value": "" + }, + "maintenanceWindow": { + "value": { + "customWindow": "Enabled", + "dayOfWeek": "0", + "startHour": "1", + "startMinute": "0" + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "", + "tags": { + "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/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfspe001' +param skuName = 'Standard_D2ds_v5' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param geoRedundantBackup = 'Enabled' +param highAvailability = 'ZoneRedundant' +param location = '' +param maintenanceWindow = { + customWindow: 'Enabled' + dayOfWeek: '0' + startHour: '1' + startMinute: '0' +} +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +``` + +
    +

    + +### Example 5: _Public access_ + +This instance deploys the module with public access and most of its features enabled. + + +

    + +via Bicep module + +```bicep +module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' = { + name: 'flexibleServerDeployment' + params: { + // Required parameters + name: 'dfpsfspub001' skuName: 'Standard_D2s_v3' tier: 'GeneralPurpose' // Non-required parameters @@ -664,7 +823,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:' // Required parameters -param name = 'dfpsfsp001' +param name = 'dfpsfspub001' param skuName = 'Standard_D2s_v3' param tier = 'GeneralPurpose' // Non-required parameters @@ -889,7 +1048,7 @@ param version = '14'

    -### Example 5: _WAF-aligned_ +### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1181,7 +1340,8 @@ param tags = { | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`maintenanceWindow`](#parameter-maintenancewindow) | object | Properties for the maintenence window. If provided, 'customWindow' property must exist and set to 'Enabled'. | | [`passwordAuth`](#parameter-passwordauth) | string | If Enabled, password authentication is enabled. | -| [`privateDnsZoneArmResourceId`](#parameter-privatednszonearmresourceid) | string | Private dns zone arm resource ID. Used when the desired connectivity mode is 'Private Access' and required when 'delegatedSubnetResourceId' is used. The Private DNS Zone must be lined to the Virtual Network referenced in 'delegatedSubnetResourceId'. | +| [`privateDnsZoneArmResourceId`](#parameter-privatednszonearmresourceid) | string | Private dns zone arm resource ID. Used when the desired connectivity mode is 'Private Access' and required when 'delegatedSubnetResourceId' is used. The Private DNS Zone must be linked to the Virtual Network referenced in 'delegatedSubnetResourceId'. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. Used when the desired connectivy mode is 'Public Access' and 'delegatedSubnetResourceId' is NOT used. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`storageSizeGB`](#parameter-storagesizegb) | int | Max storage allowed for a server. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -1677,12 +1837,374 @@ If Enabled, password authentication is enabled. ### Parameter: `privateDnsZoneArmResourceId` -Private dns zone arm resource ID. Used when the desired connectivity mode is 'Private Access' and required when 'delegatedSubnetResourceId' is used. The Private DNS Zone must be lined to the Virtual Network referenced in 'delegatedSubnetResourceId'. +Private dns zone arm resource ID. Used when the desired connectivity mode is 'Private Access' and required when 'delegatedSubnetResourceId' is used. The Private DNS Zone must be linked to the Virtual Network referenced in 'delegatedSubnetResourceId'. - Required: No - Type: string - Default: `''` +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. Used when the desired connectivy mode is 'Public Access' and 'delegatedSubnetResourceId' is NOT used. + +- 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. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | +| [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`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 | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +Fqdn that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### 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.privateDnsZoneGroupName` + +The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneResourceIds` + +The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. + +- Required: No +- Type: array + +### 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: `roleAssignments` Array of role assignments to create. @@ -1853,6 +2375,14 @@ PostgreSQL Server version. | `resourceGroupName` | string | The resource group of the deployed PostgreSQL Flexible server. | | `resourceId` | string | The resource ID of the deployed PostgreSQL Flexible server. | +## 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.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/res/db-for-postgre-sql/flexible-server/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/main.bicep index 7b24eb2bc7..c2cd387401 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/main.bicep @@ -134,7 +134,7 @@ param sourceServerResourceId string = '' @description('Optional. Delegated subnet arm resource ID. Used when the desired connectivity mode is \'Private Access\' - virtual network integration.') param delegatedSubnetResourceId string = '' -@description('Optional. Private dns zone arm resource ID. Used when the desired connectivity mode is \'Private Access\' and required when \'delegatedSubnetResourceId\' is used. The Private DNS Zone must be lined to the Virtual Network referenced in \'delegatedSubnetResourceId\'.') +@description('Optional. Private dns zone arm resource ID. Used when the desired connectivity mode is \'Private Access\' and required when \'delegatedSubnetResourceId\' is used. The Private DNS Zone must be linked to the Virtual Network referenced in \'delegatedSubnetResourceId\'.') param privateDnsZoneArmResourceId string = '' @description('Optional. The firewall rules to create in the PostgreSQL flexible server.') @@ -161,6 +161,9 @@ param enableTelemetry bool = true @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType +@description('Optional. Configuration details for private endpoints. Used when the desired connectivy mode is \'Public Access\' and \'delegatedSubnetResourceId\' is NOT used.') +param privateEndpoints privateEndpointType + var formattedUserAssignedIdentities = reduce( map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), {}, @@ -412,6 +415,59 @@ resource flexibleServer_diagnosticSettings 'Microsoft.Insights/diagnosticSetting } ] +module server_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): if (empty(delegatedSubnetResourceId)) { + name: '${uniqueString(deployment().name, location)}-flexibleserver-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(flexibleServer.id, '/'))}-${privateEndpoint.?service ?? 'postgresqlServer'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(flexibleServer.id, '/'))}-${privateEndpoint.?service ?? 'postgresqlServer'}-${index}' + properties: { + privateLinkServiceId: flexibleServer.id + groupIds: [ + privateEndpoint.?service ?? 'postgresqlServer' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(flexibleServer.id, '/'))}-${privateEndpoint.?service ?? 'postgresqlServer'}-${index}' + properties: { + privateLinkServiceId: flexibleServer.id + groupIds: [ + privateEndpoint.?service ?? 'postgresqlServer' + ] + 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 + privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName + privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + @description('The name of the deployed PostgreSQL Flexible server.') output name string = flexibleServer.name @@ -527,3 +583,81 @@ type customerManagedKeyType = { @description('Required. User assigned identity to use when fetching the customer managed key.') userAssignedIdentityResourceId: 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('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') + service: string? + + @description('Required. Resource ID of the subnet where the endpoint needs to be created.') + subnetResourceId: string + + @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') + privateDnsZoneGroupName: string? + + @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneResourceIds: 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('Required. 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? +}[]? diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.json b/avm/res/db-for-postgre-sql/flexible-server/main.json index 3e71af1f04..fde16d696e 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.json +++ b/avm/res/db-for-postgre-sql/flexible-server/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16193893481581771669" + "version": "0.28.1.47646", + "templateHash": "17059388834695026761" }, "name": "DBforPostgreSQL Flexible Servers", "description": "This module deploys a DBforPostgreSQL Flexible Server.", @@ -276,6 +276,203 @@ } }, "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 } }, "parameters": { @@ -500,7 +697,7 @@ "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. Private dns zone arm resource ID. Used when the desired connectivity mode is 'Private Access' and required when 'delegatedSubnetResourceId' is used. The Private DNS Zone must be lined to the Virtual Network referenced in 'delegatedSubnetResourceId'." + "description": "Optional. Private dns zone arm resource ID. Used when the desired connectivity mode is 'Private Access' and required when 'delegatedSubnetResourceId' is used. The Private DNS Zone must be linked to the Virtual Network referenced in 'delegatedSubnetResourceId'." } }, "firewallRules": { @@ -555,6 +752,12 @@ "metadata": { "description": "Optional. The diagnostic settings of the service." } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. Used when the desired connectivy mode is 'Public Access' and 'delegatedSubnetResourceId' is NOT used." + } } }, "variables": { @@ -780,8 +983,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17501165975344742322" + "version": "0.28.1.47646", + "templateHash": "6060199938382421423" }, "name": "DBforPostgreSQL Flexible Server Databases", "description": "This module deploys a DBforPostgreSQL Flexible Server Database.", @@ -888,8 +1091,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5110779562094536429" + "version": "0.28.1.47646", + "templateHash": "18047073594923038356" }, "name": "DBforPostgreSQL Flexible Server Firewall Rules", "description": "This module deploys a DBforPostgreSQL Flexible Server Firewall Rule.", @@ -997,8 +1200,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3802666632340288344" + "version": "0.28.1.47646", + "templateHash": "1739518705583408324" }, "name": "DBforPostgreSQL Flexible Server Configurations", "description": "This module deploys a DBforPostgreSQL Flexible Server Configuration.", @@ -1109,8 +1312,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9786947819042824705" + "version": "0.28.1.47646", + "templateHash": "18164580138640455419" }, "name": "DBforPostgreSQL Flexible Server Administrators", "description": "This module deploys a DBforPostgreSQL Flexible Server Administrator.", @@ -1196,6 +1399,669 @@ "flexibleServer", "flexibleServer_configurations" ] + }, + "server_privateEndpoints": { + "copy": { + "name": "server_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "condition": "[empty(parameters('delegatedSubnetResourceId'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-flexibleserver-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.DBforPostgreSQL/flexibleServers', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'postgresqlServer'), 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.DBforPostgreSQL/flexibleServers', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'postgresqlServer'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DBforPostgreSQL/flexibleServers', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'postgresqlServer')))))), 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.DBforPostgreSQL/flexibleServers', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'postgresqlServer'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DBforPostgreSQL/flexibleServers', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'postgresqlServer')), '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'))]" + }, + "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": [ + "flexibleServer" + ] } }, "outputs": { diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/dependencies.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/dependencies.bicep new file mode 100644 index 0000000000..adb84159b8 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/dependencies.bicep @@ -0,0 +1,52 @@ +@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: 'endpoints' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: '${split(virtualNetworkName, '-')[1]}.postgres.database.azure.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 resource ID of the created virtual network subnet for a Private Endpoint.') +output privateEndpointSubnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/main.test.bicep new file mode 100644 index 0000000000..f80ee12ba7 --- /dev/null +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public-with-pe/main.test.bicep @@ -0,0 +1,86 @@ +targetScope = 'subscription' + +metadata name = 'Public access with private endpoints' +metadata description = 'This instance deploys the module with public access and private endpoints.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-dbforpostgresql.flexibleservers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dfpsfspe' + +@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@2023-07-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 + administratorLogin: 'adminUserName' + administratorLoginPassword: password + skuName: 'Standard_D2ds_v5' + tier: 'GeneralPurpose' + geoRedundantBackup: 'Enabled' + highAvailability: 'ZoneRedundant' + maintenanceWindow: { + customWindow: 'Enabled' + dayOfWeek: '0' + startHour: '1' + startMinute: '0' + } + privateEndpoints: [ + { + subnetResourceId: nestedDependencies.outputs.privateEndpointSubnetResourceId + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + } + } +] diff --git a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep index 01b6ee55cc..8d955d531f 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/tests/e2e/public/main.test.bicep @@ -1,7 +1,7 @@ targetScope = 'subscription' metadata name = 'Public access' -metadata description = 'This instance deploys the module with public access.' +metadata description = 'This instance deploys the module with public access and most of its features enabled.' // ========== // // Parameters // @@ -15,7 +15,7 @@ param resourceGroupName string = 'dep-${namePrefix}-dbforpostgresql.flexibleserv param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'dfpsfsp' +param serviceShort string = 'dfpsfspub' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' @@ -154,5 +154,9 @@ module testDeployment '../../../main.bicep' = [ Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] } ] diff --git a/avm/res/db-for-postgre-sql/flexible-server/version.json b/avm/res/db-for-postgre-sql/flexible-server/version.json index c177b1bb58..3f863a2bec 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/version.json +++ b/avm/res/db-for-postgre-sql/flexible-server/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.4", "pathFilters": [ "./main.json" ] From ecaa2fa4b22fe417b89691df937fec2a5866bc15 Mon Sep 17 00:00:00 2001 From: Joery Grolleman <44697823+joerygrolleman@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:28:20 +0200 Subject: [PATCH 83/93] fix: Added DependsOn to Virtual Network module to prevent Network peering to start whilst subnets are being created (#3404) ## Description When creating a virtual network with subnets and network peering for the first time it causes an error, namely `Resource is in Updating state and the last operation that updated/is updating the resource is PutSubnetOperation.`. To prevent this from happening, I added a `dependsOn` on the peering to prevent the peering from being created before the subnets were created. This isn't the prettiest solution as subnets are not dependent on the peerings to succeed. Fixes #3405 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.virtual-network](https://github.com/joerygrolleman/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg)](https://github.com/joerygrolleman/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Joery Grolleman Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/network/virtual-network/main.bicep | 10 +++++++++ avm/res/network/virtual-network/main.json | 22 ++++++++++--------- .../network/virtual-network/subnet/main.json | 4 ++-- .../virtual-network-peering/main.json | 4 ++-- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/avm/res/network/virtual-network/main.bicep b/avm/res/network/virtual-network/main.bicep index c5d51b21ee..1c667905c4 100644 --- a/avm/res/network/virtual-network/main.bicep +++ b/avm/res/network/virtual-network/main.bicep @@ -174,6 +174,11 @@ module virtualNetwork_subnets 'subnet/main.bicep' = [ 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 @@ -191,6 +196,11 @@ module virtualNetwork_peering_local 'virtual-network-peering/main.bicep' = [ 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] diff --git a/avm/res/network/virtual-network/main.json b/avm/res/network/virtual-network/main.json index 48dff6ec21..6e538351c9 100644 --- a/avm/res/network/virtual-network/main.json +++ b/avm/res/network/virtual-network/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17645744687566805489" + "version": "0.30.23.60470", + "templateHash": "9022073476687436734" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -804,8 +804,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5699372618313647761" + "version": "0.30.23.60470", + "templateHash": "6677157161292207910" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -1183,8 +1183,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5206620163504251868" + "version": "0.30.23.60470", + "templateHash": "345394220621166229" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -1289,7 +1289,8 @@ } }, "dependsOn": [ - "virtualNetwork" + "virtualNetwork", + "virtualNetwork_subnets" ] }, "virtualNetwork_peering_remote": { @@ -1340,8 +1341,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5206620163504251868" + "version": "0.30.23.60470", + "templateHash": "345394220621166229" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -1446,7 +1447,8 @@ } }, "dependsOn": [ - "virtualNetwork" + "virtualNetwork", + "virtualNetwork_subnets" ] } }, diff --git a/avm/res/network/virtual-network/subnet/main.json b/avm/res/network/virtual-network/subnet/main.json index f38d007cef..09fb7ed1de 100644 --- a/avm/res/network/virtual-network/subnet/main.json +++ b/avm/res/network/virtual-network/subnet/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5699372618313647761" + "version": "0.30.23.60470", + "templateHash": "6677157161292207910" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", diff --git a/avm/res/network/virtual-network/virtual-network-peering/main.json b/avm/res/network/virtual-network/virtual-network-peering/main.json index 422a6da9b7..1c86fd7544 100644 --- a/avm/res/network/virtual-network/virtual-network-peering/main.json +++ b/avm/res/network/virtual-network/virtual-network-peering/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5206620163504251868" + "version": "0.30.23.60470", + "templateHash": "345394220621166229" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", From b673ec8840fa9eee5e71fa76bf991b0899d5714d Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Mon, 14 Oct 2024 21:30:16 +0200 Subject: [PATCH 84/93] fix: Added enforced location for ML-services (#3552) ## Description - Hardcoded test location to 'ukSouth' as 'NorthEurope' & 'EastAsia' are not supported Depends on #3553 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-ai-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-ai-environment.yml/badge.svg?branch=users%2Falsehr%2FazdaiMLLoc&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-ai-environment.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/ptn/azd/ml-ai-environment/README.md | 19 +- avm/ptn/azd/ml-ai-environment/main.bicep | 4 +- avm/ptn/azd/ml-ai-environment/main.json | 2977 +---------------- .../tests/e2e/defaults/main.test.bicep | 15 +- .../tests/e2e/max/main.test.bicep | 15 +- 5 files changed, 55 insertions(+), 2975 deletions(-) diff --git a/avm/ptn/azd/ml-ai-environment/README.md b/avm/ptn/azd/ml-ai-environment/README.md index 3dd9ecfc56..63ec2d517d 100644 --- a/avm/ptn/azd/ml-ai-environment/README.md +++ b/avm/ptn/azd/ml-ai-environment/README.md @@ -31,6 +31,7 @@ Create Azure Machine Learning workspaces of type 'Hub' and 'Project' and their r | `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) | | `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/accessPolicies` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-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) | @@ -95,7 +96,7 @@ module mlAiEnvironment 'br/public:avm/ptn/azd/ml-ai-environment:' = { // Required parameters cognitiveServicesName: 'maemincs001' hubName: 'maeminhub001' - keyVaultName: 'maeminkv00' + keyVaultName: 'maeminkv01' openAiConnectionName: 'maeminai001-connection' projectName: 'maeminpro001' searchConnectionName: 'maeminsearch001-connection' @@ -127,7 +128,7 @@ module mlAiEnvironment 'br/public:avm/ptn/azd/ml-ai-environment:' = { "value": "maeminhub001" }, "keyVaultName": { - "value": "maeminkv00" + "value": "maeminkv01" }, "openAiConnectionName": { "value": "maeminai001-connection" @@ -165,7 +166,7 @@ using 'br/public:avm/ptn/azd/ml-ai-environment:' // Required parameters param cognitiveServicesName = 'maemincs001' param hubName = 'maeminhub001' -param keyVaultName = 'maeminkv00' +param keyVaultName = 'maeminkv01' param openAiConnectionName = 'maeminai001-connection' param projectName = 'maeminpro001' param searchConnectionName = 'maeminsearch001-connection' @@ -194,7 +195,7 @@ module mlAiEnvironment 'br/public:avm/ptn/azd/ml-ai-environment:' = { // Required parameters cognitiveServicesName: 'maemaxcs001' hubName: 'maemaxhub001' - keyVaultName: 'maemaxkv001' + keyVaultName: 'maemaxkv002' openAiConnectionName: 'maemaxai001-connection' projectName: 'maemaxpro001' searchConnectionName: 'maemaxsearch001-connection' @@ -244,7 +245,7 @@ module mlAiEnvironment 'br/public:avm/ptn/azd/ml-ai-environment:' = { "value": "maemaxhub001" }, "keyVaultName": { - "value": "maemaxkv001" + "value": "maemaxkv002" }, "openAiConnectionName": { "value": "maemaxai001-connection" @@ -310,7 +311,7 @@ using 'br/public:avm/ptn/azd/ml-ai-environment:' // Required parameters param cognitiveServicesName = 'maemaxcs001' param hubName = 'maemaxhub001' -param keyVaultName = 'maemaxkv001' +param keyVaultName = 'maemaxkv002' param openAiConnectionName = 'maemaxai001-connection' param projectName = 'maemaxpro001' param searchConnectionName = 'maemaxsearch001-connection' @@ -364,7 +365,7 @@ param searchServiceName = 'maemaxsearch001' | [`location`](#parameter-location) | string | Location for all Resources. | | [`logAnalyticsName`](#parameter-loganalyticsname) | string | The Log Analytics resource name. | | [`openAiConnectionName`](#parameter-openaiconnectionname) | string | The Open AI connection name. | -| [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. | +| [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs, or between 1 and 3 inclusive for basic SKU. | | [`searchConnectionName`](#parameter-searchconnectionname) | string | The Azure Search connection name. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`userAssignedtName`](#parameter-userassignedtname) | string | The User Assigned Identity resource name. | @@ -467,7 +468,7 @@ The Open AI connection name. ### Parameter: `replicaCount` -The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. +The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs, or between 1 and 3 inclusive for basic SKU. - Required: No - Type: int @@ -537,7 +538,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | | `br/public:avm/ptn/azd/ml-hub-dependencies:0.1.0` | Remote reference | -| `br/public:avm/ptn/azd/ml-project:0.1.0` | Remote reference | +| `br/public:avm/ptn/azd/ml-project:0.1.1` | Remote reference | | `br/public:avm/res/machine-learning-services/workspace:0.8.1` | Remote reference | ## Data Collection diff --git a/avm/ptn/azd/ml-ai-environment/main.bicep b/avm/ptn/azd/ml-ai-environment/main.bicep index 97dcd25920..93449fef7d 100644 --- a/avm/ptn/azd/ml-ai-environment/main.bicep +++ b/avm/ptn/azd/ml-ai-environment/main.bicep @@ -60,7 +60,7 @@ param searchConnectionName string @description('Optional. The User Assigned Identity resource name.') param userAssignedtName string -@description('Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU.') +@description('Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs, or between 1 and 3 inclusive for basic SKU.') @minValue(1) @maxValue(12) param replicaCount int = 1 @@ -123,7 +123,7 @@ module hub './modules/hub.bicep' = { } } -module project 'br/public:avm/ptn/azd/ml-project:0.1.0' = { +module project 'br/public:avm/ptn/azd/ml-project:0.1.1' = { name: '${uniqueString(deployment().name, location)}-project' params: { name: projectName diff --git a/avm/ptn/azd/ml-ai-environment/main.json b/avm/ptn/azd/ml-ai-environment/main.json index cb3b56312e..2f3eba97f0 100644 --- a/avm/ptn/azd/ml-ai-environment/main.json +++ b/avm/ptn/azd/ml-ai-environment/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "149833058937281725" + "templateHash": "197970377593675839" }, "name": "Azd Azure Machine Learning Environment", "description": "Create Azure Machine Learning workspaces of type 'Hub' and 'Project' and their required dependencies.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -124,7 +124,7 @@ "minValue": 1, "maxValue": 12, "metadata": { - "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs, or between 1 and 3 inclusive for basic SKU." } } }, @@ -22961,7 +22961,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "11662488567540742511" + "templateHash": "17734235406639655521" }, "name": "Azd Machine Learning workspace", "description": "Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -23103,11 +23103,34 @@ } }, "resources": { + "keyVault::keyVaultAccess": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": [ + { + "objectId": "[reference('project').outputs.systemAssignedMIPrincipalId.value]", + "permissions": { + "secrets": [ + "get", + "list" + ] + }, + "tenantId": "[tenant().tenantId]" + } + ] + }, + "dependsOn": [ + "keyVault", + "project" + ] + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.ptn.azd-mlproject.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.ptn.azd-mlproject.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -26934,2952 +26957,6 @@ } } }, - "keyVaultAccess": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('keyVaultName')]" - }, - "accessPolicies": { - "value": [ - { - "objectId": "[reference('project').outputs.systemAssignedMIPrincipalId.value]", - "permissions": { - "secrets": [ - "get", - "list" - ] - } - } - ] - }, - "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.29.47.4906", - "templateHash": "10085839006881327962" - }, - "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": { - "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": "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": "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('0.9.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" - } - } - } - } - }, - "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.29.47.4906", - "templateHash": "7494731697751039419" - }, - "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')]" - }, - "dependsOn": [ - "keyVault" - ] - } - }, - "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.29.47.4906", - "templateHash": "114626909766354577" - }, - "name": "Key Vault Secrets", - "description": "This module deploys a Key Vault Secret.", - "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 - } - }, - "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": { - "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')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "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'))]" - }, - "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.29.47.4906", - "templateHash": "14269695922191217406" - }, - "name": "Key Vault Keys", - "description": "This module deploys a Key Vault Key.", - "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 - } - }, - "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": { - "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": { - "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())]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "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": { - "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], '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": [ - "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", - "metadata": { - "description": "The private endpoints of the key vault." - }, - "copy": { - "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(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": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", - "customDnsConfig": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", - "networkInterfaceIds": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "keyVault", - "project" - ] - }, "mlServiceRoleAssigned": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", diff --git a/avm/ptn/azd/ml-ai-environment/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/ml-ai-environment/tests/e2e/defaults/main.test.bicep index ec8f688f21..ad03c6ec9e 100644 --- a/avm/ptn/azd/ml-ai-environment/tests/e2e/defaults/main.test.bicep +++ b/avm/ptn/azd/ml-ai-environment/tests/e2e/defaults/main.test.bicep @@ -11,15 +11,16 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-azd-ml-ai-environment-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'maemin' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' +// Set to fixed location as the deployment does not work in most rotated locations +// Right now (2024/10) the following locations are supported for 'AIServices': uksouth, eastus +param enforcedLocation string = 'uksouth' + // ============ // // Dependencies // // ============ // @@ -28,7 +29,7 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } // ============== // @@ -39,10 +40,10 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation - keyVaultName: '${namePrefix}${serviceShort}kv00' + location: enforcedLocation + keyVaultName: '${namePrefix}${serviceShort}kv01' storageAccountName: '${namePrefix}${serviceShort}sa001' hubName: '${namePrefix}${serviceShort}hub001' projectName: '${namePrefix}${serviceShort}pro001' diff --git a/avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep b/avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep index 13556d5d28..23707982e8 100644 --- a/avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep +++ b/avm/ptn/azd/ml-ai-environment/tests/e2e/max/main.test.bicep @@ -11,15 +11,16 @@ metadata description = 'This instance deploys the module using large parameters. @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-azd-ml-ai-environment-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') param serviceShort string = 'maemax' @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_#' +// Set to fixed location as the deployment does not work in most rotated locations +// Right now (2024/10) the following locations are supported for 'AIServices': uksouth, eastus +param enforcedLocation string = 'eastus' + // ============ // // Dependencies // // ============ // @@ -28,7 +29,7 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } // ============== // @@ -39,11 +40,11 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation hubName: '${namePrefix}${serviceShort}hub001' - keyVaultName: '${namePrefix}${serviceShort}kv001' + keyVaultName: '${namePrefix}${serviceShort}kv002' cognitiveServicesName: '${namePrefix}${serviceShort}cs001' projectName: '${namePrefix}${serviceShort}pro001' storageAccountName: '${namePrefix}${serviceShort}sta001' From dc6d10f4ee83f2bafbfa1d17a69922c8706e5847 Mon Sep 17 00:00:00 2001 From: Fabio Masciotra Date: Mon, 14 Oct 2024 22:56:28 +0200 Subject: [PATCH 85/93] feat: module `avm/res/network/virtual-network-gateway` (#3324) ## Description Applied the same approach we did for several other modules that may or must use a public IP, allowing the use of an existing Public IP (resourceID) Closes #3061 ## Pipeline Reference [![avm.res.network.virtual-network-gateway](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml/badge.svg?branch=vnetgw-pip)](https://github.com/fabmas/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml) | Pipeline | | -------- | | | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- .../network/virtual-network-gateway/README.md | 486 ++++++++++++------ .../virtual-network-gateway/main.bicep | 87 +++- .../network/virtual-network-gateway/main.json | 56 +- .../nat-rule/main.json | 4 +- .../tests/e2e/aadvpn/dependencies.bicep | 30 -- .../dependencies.bicep | 96 ++++ .../activeActiveExistingPip/main.test.bicep | 88 ++++ .../dependencies.bicep | 74 +++ .../main.test.bicep | 36 +- .../tests/e2e/expressRoute/main.test.bicep | 2 +- .../tests/e2e/max/main.test.bicep | 2 +- .../virtual-network-gateway/version.json | 2 +- 12 files changed, 715 insertions(+), 248 deletions(-) delete mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/dependencies.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/dependencies.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/main.test.bicep create mode 100644 avm/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/dependencies.bicep rename avm/res/network/virtual-network-gateway/tests/e2e/{aadvpn => activePassiveExistingPip}/main.test.bicep (68%) diff --git a/avm/res/network/virtual-network-gateway/README.md b/avm/res/network/virtual-network-gateway/README.md index 290070237e..4d876db399 100644 --- a/avm/res/network/virtual-network-gateway/README.md +++ b/avm/res/network/virtual-network-gateway/README.md @@ -30,22 +30,23 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-network-gateway:`. -- [AAD-VPN](#example-1-aad-vpn) +- [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 with BGP settings](#example-3-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 without BGP settings](#example-6-vpn-active-passive-without-bgp-settings) -- [Using only defaults](#example-7-using-only-defaults) -- [ExpressRoute](#example-8-expressroute) -- [Using large parameter set](#example-9-using-large-parameter-set) -- [Using SKU without Availability Zones](#example-10-using-sku-without-availability-zones) -- [VPN](#example-11-vpn) -- [WAF-aligned](#example-12-waf-aligned) +- [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: _AAD-VPN_ +### Example 1: _VPN Active Active with BGP settings_ -This instance deploys the module with the AAD set of required parameters. +This instance deploys the module with the VPN Active Active with BGP settings.

    @@ -58,15 +59,20 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: params: { // Required parameters clusterSettings: { - clusterMode: 'activePassiveNoBgp' + clusterMode: 'activeActiveBgp' } gatewayType: 'Vpn' - name: 'nvgavpn001' + name: 'nvgaab001' vNetResourceId: '' // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true domainNameLabel: [ - 'dm-nvgavpn' + 'dm-nvgaab' ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' location: '' publicIpZones: [ 1 @@ -74,17 +80,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] skuName: 'VpnGw2AZ' - vpnClientAadConfiguration: { - aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' - aadIssuer: '' - aadTenant: '' - vpnAuthenticationTypes: [ - 'AAD' - ] - vpnClientProtocols: [ - 'OpenVPN' - ] - } + vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } } @@ -105,24 +101,39 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: // Required parameters "clusterSettings": { "value": { - "clusterMode": "activePassiveNoBgp" + "clusterMode": "activeActiveBgp" } }, "gatewayType": { "value": "Vpn" }, "name": { - "value": "nvgavpn001" + "value": "nvgaab001" }, "vNetResourceId": { "value": "" }, // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, "domainNameLabel": { "value": [ - "dm-nvgavpn" + "dm-nvgaab" ] }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, "location": { "value": "" }, @@ -136,18 +147,8 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "skuName": { "value": "VpnGw2AZ" }, - "vpnClientAadConfiguration": { - "value": { - "aadAudience": "41b23e61-6c1e-4545-b367-cd054e0ed4b4", - "aadIssuer": "", - "aadTenant": "", - "vpnAuthenticationTypes": [ - "AAD" - ], - "vpnClientProtocols": [ - "OpenVPN" - ] - } + "vpnGatewayGeneration": { + "value": "Generation2" }, "vpnType": { "value": "RouteBased" @@ -168,15 +169,20 @@ using 'br/public:avm/res/network/virtual-network-gateway:' // Required parameters param clusterSettings = { - clusterMode: 'activePassiveNoBgp' + clusterMode: 'activeActiveBgp' } param gatewayType = 'Vpn' -param name = 'nvgavpn001' +param name = 'nvgaab001' param vNetResourceId = '' // Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true param domainNameLabel = [ - 'dm-nvgavpn' + 'dm-nvgaab' ] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' param location = '' param publicIpZones = [ 1 @@ -184,17 +190,7 @@ param publicIpZones = [ 3 ] param skuName = 'VpnGw2AZ' -param vpnClientAadConfiguration = { - aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' - aadIssuer: '' - aadTenant: '' - vpnAuthenticationTypes: [ - 'AAD' - ] - vpnClientProtocols: [ - 'OpenVPN' - ] -} +param vpnGatewayGeneration = 'Generation2' param vpnType = 'RouteBased' ``` @@ -203,7 +199,7 @@ param vpnType = 'RouteBased' ### Example 2: _VPN Active Active with BGP settings_ -This instance deploys the module with the VPN Active Active with BGP settings. +This instance deploys the module with the VPN Active Active with APIPA BGP settings.
    @@ -217,15 +213,23 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: // 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: 'nvgaab001' + name: 'nvgaaa001' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true disableIPSecReplayProtection: true domainNameLabel: [ - 'dm-nvgaab' + 'dm-nvgaaa' ] enableBgpRouteTranslationForNat: true enablePrivateIpAddress: true @@ -258,14 +262,22 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: // Required parameters "clusterSettings": { "value": { - "clusterMode": "activeActiveBgp" + "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": "nvgaab001" + "value": "nvgaaa001" }, "vNetResourceId": { "value": "" @@ -279,7 +291,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: }, "domainNameLabel": { "value": [ - "dm-nvgaab" + "dm-nvgaaa" ] }, "enableBgpRouteTranslationForNat": { @@ -327,15 +339,23 @@ 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 = 'nvgaab001' +param name = 'nvgaaa001' param vNetResourceId = '' // Non-required parameters param allowRemoteVnetTraffic = true param disableIPSecReplayProtection = true param domainNameLabel = [ - 'dm-nvgaab' + 'dm-nvgaaa' ] param enableBgpRouteTranslationForNat = true param enablePrivateIpAddress = true @@ -354,9 +374,9 @@ param vpnType = 'RouteBased'

    -### Example 3: _VPN Active Active with BGP settings_ +### Example 3: _VPN Active Active without BGP settings using two existent Public IPs_ -This instance deploys the module with the VPN Active Active with APIPA BGP settings. +This instance deploys the module with the VPN Active Active without BGP settings.

    @@ -369,27 +389,21 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: params: { // Required parameters clusterSettings: { - clusterMode: 'activeActiveBgp' - customBgpIpAddresses: [ - '169.254.21.4' - '169.254.21.5' - ] - secondCustomBgpIpAddresses: [ - '169.254.22.4' - '169.254.22.5' - ] + clusterMode: 'activeActiveNoBgp' + existingSecondPipResourceId: '' } gatewayType: 'Vpn' - name: 'nvgaaa001' + name: 'nvgaaep001' vNetResourceId: '' // Non-required parameters allowRemoteVnetTraffic: true disableIPSecReplayProtection: true domainNameLabel: [ - 'dm-nvgaaa' + 'dm-nvgaaep' ] enableBgpRouteTranslationForNat: true enablePrivateIpAddress: true + existingFirstPipResourceId: '' gatewayDefaultSiteLocalNetworkGatewayId: '' location: '' publicIpZones: [ @@ -419,22 +433,15 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: // Required parameters "clusterSettings": { "value": { - "clusterMode": "activeActiveBgp", - "customBgpIpAddresses": [ - "169.254.21.4", - "169.254.21.5" - ], - "secondCustomBgpIpAddresses": [ - "169.254.22.4", - "169.254.22.5" - ] + "clusterMode": "activeActiveNoBgp", + "existingSecondPipResourceId": "" } }, "gatewayType": { "value": "Vpn" }, "name": { - "value": "nvgaaa001" + "value": "nvgaaep001" }, "vNetResourceId": { "value": "" @@ -448,7 +455,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: }, "domainNameLabel": { "value": [ - "dm-nvgaaa" + "dm-nvgaaep" ] }, "enableBgpRouteTranslationForNat": { @@ -457,6 +464,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "enablePrivateIpAddress": { "value": true }, + "existingFirstPipResourceId": { + "value": "" + }, "gatewayDefaultSiteLocalNetworkGatewayId": { "value": "" }, @@ -495,27 +505,21 @@ 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' - ] + clusterMode: 'activeActiveNoBgp' + existingSecondPipResourceId: '' } param gatewayType = 'Vpn' -param name = 'nvgaaa001' +param name = 'nvgaaep001' param vNetResourceId = '' // Non-required parameters param allowRemoteVnetTraffic = true param disableIPSecReplayProtection = true param domainNameLabel = [ - 'dm-nvgaaa' + 'dm-nvgaaep' ] param enableBgpRouteTranslationForNat = true param enablePrivateIpAddress = true +param existingFirstPipResourceId = '' param gatewayDefaultSiteLocalNetworkGatewayId = '' param location = '' param publicIpZones = [ @@ -852,7 +856,180 @@ param vpnType = 'RouteBased'

    -### Example 6: _VPN Active Passive without BGP settings_ +### 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. @@ -1005,7 +1182,7 @@ param vpnType = 'RouteBased'

    -### Example 7: _Using only defaults_ +### Example 8: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -1112,7 +1289,7 @@ param skuName = 'VpnGw2AZ'

    -### Example 8: _ExpressRoute_ +### Example 9: _ExpressRoute_ This instance deploys the module with the ExpressRoute set of required parameters. @@ -1136,7 +1313,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: domainNameLabel: [ 'dm-nvger' ] - gatewayPipName: 'pip-nvger' + firstPipName: 'pip-nvger' location: '' publicIpZones: [ 1 @@ -1181,7 +1358,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "dm-nvger" ] }, - "gatewayPipName": { + "firstPipName": { "value": "pip-nvger" }, "location": { @@ -1222,7 +1399,7 @@ param vNetResourceId = '' param domainNameLabel = [ 'dm-nvger' ] -param gatewayPipName = 'pip-nvger' +param firstPipName = 'pip-nvger' param location = '' param publicIpZones = [ 1 @@ -1235,7 +1412,7 @@ param skuName = 'ErGw1AZ'

    -### Example 9: _Using large parameter set_ +### Example 10: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -1250,7 +1427,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: params: { // Required parameters clusterSettings: { - activeGatewayPipName: 'nvgmax001-pip2' clusterMode: 'activeActiveBgp' customBgpIpAddresses: [ '169.254.21.4' @@ -1260,6 +1436,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: '169.254.22.4' '169.254.22.5' ] + secondPipName: 'nvgmax001-pip2' } gatewayType: 'Vpn' name: 'nvgmax001' @@ -1377,7 +1554,6 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: // Required parameters "clusterSettings": { "value": { - "activeGatewayPipName": "nvgmax001-pip2", "clusterMode": "activeActiveBgp", "customBgpIpAddresses": [ "169.254.21.4", @@ -1386,7 +1562,8 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "secondCustomBgpIpAddresses": [ "169.254.22.4", "169.254.22.5" - ] + ], + "secondPipName": "nvgmax001-pip2" } }, "gatewayType": { @@ -1540,7 +1717,6 @@ using 'br/public:avm/res/network/virtual-network-gateway:' // Required parameters param clusterSettings = { - activeGatewayPipName: 'nvgmax001-pip2' clusterMode: 'activeActiveBgp' customBgpIpAddresses: [ '169.254.21.4' @@ -1550,6 +1726,7 @@ param clusterSettings = { '169.254.22.4' '169.254.22.5' ] + secondPipName: 'nvgmax001-pip2' } param gatewayType = 'Vpn' param name = 'nvgmax001' @@ -1653,7 +1830,7 @@ param vpnType = 'RouteBased'

    -### Example 10: _Using SKU without Availability Zones_ +### Example 11: _Using SKU without Availability Zones_ This instance deploys the module with a SKU that does not support Availability Zones. @@ -1748,7 +1925,7 @@ param skuName = 'VpnGw1'

    -### Example 11: _VPN_ +### Example 12: _VPN_ This instance deploys the module with the VPN set of required parameters. @@ -1901,7 +2078,7 @@ param vpnType = 'RouteBased'

    -### Example 12: _WAF-aligned_ +### Example 13: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -2269,6 +2446,7 @@ param vpnType = 'RouteBased' | [`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** @@ -2281,13 +2459,14 @@ param vpnType = 'RouteBased' | [`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 configuration, 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. | +| [`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. | -| [`gatewayPipName`](#parameter-gatewaypipname) | string | Specifies the name of the Public IP used by the Virtual Network Gateway. If it's not provided, a '-pip' suffix will be appended to the gateway's name. | | [`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. | @@ -2295,7 +2474,6 @@ param vpnType = 'RouteBased' | [`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. | -| [`skuName`](#parameter-skuname) | string | The SKU of the Gateway. | | [`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. | @@ -2330,6 +2508,36 @@ 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. @@ -2525,7 +2733,7 @@ disableIPSecReplayProtection flag. Used for VPN Gateways. ### Parameter: `domainNameLabel` -DNS name(s) of the Public IP resource(s). If you enabled active-active configuration, 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. +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 @@ -2563,22 +2771,30 @@ Enable/Disable usage telemetry for module. - Type: bool - Default: `True` -### Parameter: `gatewayDefaultSiteLocalNetworkGatewayId` +### Parameter: `existingFirstPipResourceId` -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. +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: `gatewayPipName` +### Parameter: `firstPipName` -Specifies the name of the Public IP used by the Virtual Network Gateway. If it's not provided, a '-pip' suffix will be appended to the gateway's name. +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. @@ -2904,36 +3120,6 @@ The principal type of the assigned principal ID. ] ``` -### 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: `tags` Tags of the resource. @@ -2992,7 +3178,7 @@ Specifies the VPN type. | Output | Type | Description | | :-- | :-- | :-- | -| `activeActive` | bool | Shows if the virtual network gateway is configured in active-active mode. | +| `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. | diff --git a/avm/res/network/virtual-network-gateway/main.bicep b/avm/res/network/virtual-network-gateway/main.bicep index 4cf0d87c15..50b856ea0e 100644 --- a/avm/res/network/virtual-network-gateway/main.bicep +++ b/avm/res/network/virtual-network-gateway/main.bicep @@ -8,8 +8,11 @@ param name string @description('Optional. Location for all resources.') param location string = resourceGroup().location -@description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway. If it\'s not provided, a \'-pip\' suffix will be appended to the gateway\'s name.') -param gatewayPipName string = '${name}-pip1' +@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 = '' @@ -21,7 +24,7 @@ param publicIpZones array = [ 3 ] -@description('Optional. DNS name(s) of the Public IP resource(s). If you enabled active-active configuration, 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.') +@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.') @@ -39,7 +42,7 @@ param gatewayType string ]) param vpnGatewayGeneration string = 'None' -@description('Optional. The SKU of the Gateway.') +@description('Required. The SKU of the Gateway.') @allowed([ 'Basic' 'VpnGw1' @@ -143,18 +146,26 @@ var isBgp = (clusterSettings.clusterMode == 'activeActiveBgp' || clusterSettings var isActiveActive = (clusterSettings.clusterMode == 'activeActiveNoBgp' || clusterSettings.clusterMode == 'activeActiveBgp') && !isExpressRoute -var activeGatewayPipNameVar = isActiveActive ? (clusterSettings.?activeGatewayPipName ?? '${name}-pip2') : null +var existingSecondPipResourceIdVar = isActiveActive ? clusterSettings.?existingSecondPipResourceId : null -var virtualGatewayPipNameVar = isActiveActive - ? [ - gatewayPipName - activeGatewayPipNameVar - ] - : [ - gatewayPipName - ] +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) +// Potential BGP configurations (Active-Active vs Active-Passive) var bgpSettingsVar = isActiveActive ? { asn: clusterSettings.?asn ?? 65515 @@ -179,7 +190,7 @@ var bgpSettingsVar = isActiveActive ] } -// Potential IP configurations (active-active vs active-passive) +// Potential IP configurations (Active-Active vs Active-Passive) var ipConfiguration = isActiveActive ? [ { @@ -188,8 +199,11 @@ var ipConfiguration = isActiveActive subnet: { id: '${vNetResourceId}/subnets/GatewaySubnet' } + // Use existing Public IP, new Public IP created in this module publicIPAddress: { - id: az.resourceId('Microsoft.Network/publicIPAddresses', gatewayPipName) + id: !empty(existingFirstPipResourceId) + ? existingFirstPipResourceId + : az.resourceId('Microsoft.Network/publicIPAddresses', firstPipName) } } name: 'vNetGatewayConfig1' @@ -202,8 +216,12 @@ var ipConfiguration = isActiveActive } publicIPAddress: { id: isActiveActive - ? az.resourceId('Microsoft.Network/publicIPAddresses', activeGatewayPipNameVar) - : az.resourceId('Microsoft.Network/publicIPAddresses', gatewayPipName) + ? !empty(existingSecondPipResourceIdVar) + ? existingSecondPipResourceIdVar + : az.resourceId('Microsoft.Network/publicIPAddresses', secondPipNameVar) + : !empty(existingFirstPipResourceId) + ? existingFirstPipResourceId + : az.resourceId('Microsoft.Network/publicIPAddresses', firstPipName) } } name: 'vNetGatewayConfig2' @@ -217,7 +235,9 @@ var ipConfiguration = isActiveActive id: '${vNetResourceId}/subnets/GatewaySubnet' } publicIPAddress: { - id: az.resourceId('Microsoft.Network/publicIPAddresses', gatewayPipName) + id: !empty(existingFirstPipResourceId) + ? existingFirstPipResourceId + : az.resourceId('Microsoft.Network/publicIPAddresses', firstPipName) } } name: 'vNetGatewayConfig1' @@ -323,7 +343,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT // Public IPs @batchSize(1) module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = [ - for (virtualGatewayPublicIpName, index) in virtualGatewayPipNameVar: { + for (virtualGatewayPublicIpName, index) in arrayPipNameVar: { name: virtualGatewayPublicIpName params: { name: virtualGatewayPublicIpName @@ -336,7 +356,7 @@ module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = [ skuName: skuName == 'Basic' ? 'Basic' : 'Standard' zones: skuName != 'Basic' ? publicIpZones : [] dnsSettings: { - domainNameLabel: length(virtualGatewayPipNameVar) == length(domainNameLabel) + domainNameLabel: length(arrayPipNameVar) == length(domainNameLabel) ? domainNameLabel[index] : virtualGatewayPublicIpName domainNameLabelScope: '' @@ -468,7 +488,7 @@ 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.') +@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.') @@ -557,17 +577,25 @@ type diagnosticSettingType = { }[]? type activePassiveNoBgpType = { + clusterMode: 'activePassiveNoBgp' + } type activeActiveNoBgpType = { + clusterMode: 'activeActiveNoBgp' - @description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') - activeGatewayPipName: string? + @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.') @@ -580,11 +608,15 @@ type activePassiveBgpType = { } type activeActiveBgpType = { + clusterMode: 'activeActiveBgp' - @description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') - activeGatewayPipName: string? - + @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) @@ -592,7 +624,6 @@ type activeActiveBgpType = { @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[]? } diff --git a/avm/res/network/virtual-network-gateway/main.json b/avm/res/network/virtual-network-gateway/main.json index 5badcfef95..24ec2a7c45 100644 --- a/avm/res/network/virtual-network-gateway/main.json +++ b/avm/res/network/virtual-network-gateway/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "6347373659148864152" + "templateHash": "1499507825797406827" }, "name": "Virtual Network Gateways", "description": "This module deploys a Virtual Network Gateway.", @@ -251,11 +251,18 @@ "activeActiveNoBgp" ] }, - "activeGatewayPipName": { + "existingSecondPipResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip2' suffix will be appended to the gateway's name." + "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." } } } @@ -299,11 +306,18 @@ "activeActiveBgp" ] }, - "activeGatewayPipName": { + "existingSecondPipResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip2' suffix will be appended to the gateway's name." + "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": { @@ -372,11 +386,18 @@ "description": "Optional. Location for all resources." } }, - "gatewayPipName": { + "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 used by the Virtual Network Gateway. If it's not provided, a '-pip' suffix will be appended to the gateway's name." + "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": { @@ -401,7 +422,7 @@ "type": "array", "defaultValue": [], "metadata": { - "description": "Optional. DNS name(s) of the Public IP resource(s). If you enabled active-active configuration, 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." + "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": { @@ -449,7 +470,7 @@ "ErGw3AZ" ], "metadata": { - "description": "Optional. The SKU of the Gateway." + "description": "Required. The SKU of the Gateway." } }, "vpnType": { @@ -611,10 +632,11 @@ "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')))]", - "activeGatewayPipNameVar": "[if(variables('isActiveActive'), coalesce(tryGet(parameters('clusterSettings'), 'activeGatewayPipName'), format('{0}-pip2', parameters('name'))), null())]", - "virtualGatewayPipNameVar": "[if(variables('isActiveActive'), createArray(parameters('gatewayPipName'), variables('activeGatewayPipNameVar')), createArray(parameters('gatewayPipName')))]", + "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', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1'), createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(variables('isActiveActive'), resourceId('Microsoft.Network/publicIPAddresses', variables('activeGatewayPipNameVar')), resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName'))))), 'name', 'vNetGatewayConfig2')), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1')))]", + "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')]", @@ -757,13 +779,13 @@ "publicIPAddress": { "copy": { "name": "publicIPAddress", - "count": "[length(variables('virtualGatewayPipNameVar'))]", + "count": "[length(variables('arrayPipNameVar'))]", "mode": "serial", "batchSize": 1 }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[variables('virtualGatewayPipNameVar')[copyIndex()]]", + "name": "[variables('arrayPipNameVar')[copyIndex()]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -771,7 +793,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[variables('virtualGatewayPipNameVar')[copyIndex()]]" + "value": "[variables('arrayPipNameVar')[copyIndex()]]" }, "diagnosticSettings": { "value": "[parameters('publicIpDiagnosticSettings')]" @@ -793,7 +815,7 @@ "zones": "[if(not(equals(parameters('skuName'), 'Basic')), createObject('value', parameters('publicIpZones')), createObject('value', createArray()))]", "dnsSettings": { "value": { - "domainNameLabel": "[if(equals(length(variables('virtualGatewayPipNameVar')), length(parameters('domainNameLabel'))), parameters('domainNameLabel')[copyIndex()], variables('virtualGatewayPipNameVar')[copyIndex()])]", + "domainNameLabel": "[if(equals(length(variables('arrayPipNameVar')), length(parameters('domainNameLabel'))), parameters('domainNameLabel')[copyIndex()], variables('arrayPipNameVar')[copyIndex()])]", "domainNameLabelScope": "" } } @@ -1595,7 +1617,7 @@ "activeActive": { "type": "bool", "metadata": { - "description": "Shows if the virtual network gateway is configured in active-active mode." + "description": "Shows if the virtual network gateway is configured in Active-Active mode." }, "value": "[reference('virtualNetworkGateway').activeActive]" }, diff --git a/avm/res/network/virtual-network-gateway/nat-rule/main.json b/avm/res/network/virtual-network-gateway/nat-rule/main.json index c23f033ec3..bbbe1187e9 100644 --- a/avm/res/network/virtual-network-gateway/nat-rule/main.json +++ b/avm/res/network/virtual-network-gateway/nat-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "915174536118171652" + "version": "0.30.23.60470", + "templateHash": "15500017864202979057" }, "name": "VPN Gateway NAT Rules", "description": "This module deploys a Virtual Network Gateway NAT Rule.", diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/dependencies.bicep deleted file mode 100644 index 223faddfbd..0000000000 --- a/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/dependencies.bicep +++ /dev/null @@ -1,30 +0,0 @@ -@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/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/dependencies.bicep new file mode 100644 index 0000000000..8c33f30087 --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/main.test.bicep new file mode 100644 index 0000000000..5a0f74ba0b --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/dependencies.bicep new file mode 100644 index 0000000000..61e10ff9da --- /dev/null +++ b/avm/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/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/main.test.bicep similarity index 68% rename from avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep rename to avm/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/main.test.bicep index 09457de2bd..27c179eef4 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/main.test.bicep @@ -1,7 +1,7 @@ targetScope = 'subscription' -metadata name = 'AAD-VPN' -metadata description = 'This instance deploys the module with the AAD set of required parameters.' +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 // @@ -15,7 +15,7 @@ param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgatewa param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'nvgavpn' +param serviceShort string = 'nvgapep' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' @@ -37,6 +37,8 @@ module nestedDependencies 'dependencies.bicep' = { params: { location: resourceLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + existingFirstPipName: 'dep-${namePrefix}-pip-${serviceShort}-existing1' } } @@ -52,12 +54,17 @@ module testDeployment '../../../main.bicep' = [ params: { location: resourceLocation name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - clusterSettings:{ - clusterMode: 'activePassiveNoBgp' - } + existingFirstPipResourceId: nestedDependencies.outputs.existingFirstPipResourceId + clusterSettings: { + clusterMode:'activePassiveBgp' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + asn: 65815 + } + domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] @@ -66,19 +73,12 @@ module testDeployment '../../../main.bicep' = [ 2 3 ] - vpnClientAadConfiguration: { - // The Application ID of the "Azure VPN" Azure AD Enterprise App for Azure Public - aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' - aadIssuer: 'https://sts.windows.net/${tenant().tenantId}/' - aadTenant: '${environment().authentication.loginEndpoint}/${tenant().tenantId}/' - vpnAuthenticationTypes: [ - 'AAD' - ] - vpnClientProtocols: [ - 'OpenVPN' - ] - } vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true } dependsOn: [ nestedDependencies diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep index 600e374025..1e1790c927 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep @@ -61,7 +61,7 @@ module testDeployment '../../../main.bicep' = [ domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] - gatewayPipName: '${namePrefix}-pip-${serviceShort}' + firstPipName: '${namePrefix}-pip-${serviceShort}' publicIpZones: [ 1 2 diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep index b0314fa4dc..65139ad991 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep @@ -74,7 +74,7 @@ module testDeployment '../../../main.bicep' = [ vNetResourceId: nestedDependencies.outputs.vnetResourceId clusterSettings:{ clusterMode: 'activeActiveBgp' - activeGatewayPipName: '${namePrefix}${serviceShort}001-pip2' + secondPipName: '${namePrefix}${serviceShort}001-pip2' customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] secondCustomBgpIpAddresses: ['169.254.22.4','169.254.22.5'] } diff --git a/avm/res/network/virtual-network-gateway/version.json b/avm/res/network/virtual-network-gateway/version.json index 13669e6601..ea4f3b6e67 100644 --- a/avm/res/network/virtual-network-gateway/version.json +++ b/avm/res/network/virtual-network-gateway/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.4", + "version": "0.5", "pathFilters": [ "./main.json" ] From 1c3d76ba7d39be92b2d087b0585adfe7a485088c Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 15 Oct 2024 00:45:31 +0200 Subject: [PATCH 86/93] feat: Updated RBAC schema to latest for ServerFarm (#3520) ## Description - Updated RBAC schema to latest for ServerFarm ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.web.serverfarm](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=users%2Falsehr%2FserverFarmRBAC&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/res/web/serverfarm/README.md | 14 ++++++++ avm/res/web/serverfarm/main.bicep | 25 +++++++++----- avm/res/web/serverfarm/main.json | 34 +++++++++++++------ .../serverfarm/tests/e2e/max/main.test.bicep | 2 ++ avm/res/web/serverfarm/version.json | 4 +-- 5 files changed, 59 insertions(+), 20 deletions(-) diff --git a/avm/res/web/serverfarm/README.md b/avm/res/web/serverfarm/README.md index eb15593b7c..4ae5c24824 100644 --- a/avm/res/web/serverfarm/README.md +++ b/avm/res/web/serverfarm/README.md @@ -134,11 +134,13 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { perSiteScaling: true roleAssignments: [ { + name: '97fc1da9-bfe4-409d-b17a-da9a82fad0d0' principalId: '' principalType: 'ServicePrincipal' roleDefinitionIdOrName: 'Owner' } { + name: '' principalId: '' principalType: 'ServicePrincipal' roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' @@ -212,11 +214,13 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "roleAssignments": { "value": [ { + "name": "97fc1da9-bfe4-409d-b17a-da9a82fad0d0", "principalId": "", "principalType": "ServicePrincipal", "roleDefinitionIdOrName": "Owner" }, { + "name": "", "principalId": "", "principalType": "ServicePrincipal", "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" @@ -284,11 +288,13 @@ param lock = { param perSiteScaling = true param roleAssignments = [ { + name: '97fc1da9-bfe4-409d-b17a-da9a82fad0d0' principalId: '' principalType: 'ServicePrincipal' roleDefinitionIdOrName: 'Owner' } { + name: '' principalId: '' principalType: 'ServicePrincipal' roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' @@ -763,6 +769,7 @@ Array of role assignments to create. | [`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` @@ -813,6 +820,13 @@ 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. diff --git a/avm/res/web/serverfarm/main.bicep b/avm/res/web/serverfarm/main.bicep index 3d04b2f664..38bbc58e65 100644 --- a/avm/res/web/serverfarm/main.bicep +++ b/avm/res/web/serverfarm/main.bicep @@ -104,6 +104,17 @@ var builtInRoleNames = { ) } +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.web-serverfarm.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' @@ -184,15 +195,10 @@ resource appServicePlan_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!e } resource appServicePlan_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ - for (roleAssignment, index) in (roleAssignments ?? []): { - name: guid(appServicePlan.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(appServicePlan.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) properties: { - roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( - roleAssignment.roleDefinitionIdOrName, - '/providers/Microsoft.Authorization/roleDefinitions/' - ) - ? roleAssignment.roleDefinitionIdOrName - : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + roleDefinitionId: roleAssignment.roleDefinitionId principalId: roleAssignment.principalId description: roleAssignment.?description principalType: roleAssignment.?principalType @@ -229,6 +235,9 @@ type lockType = { }? 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 diff --git a/avm/res/web/serverfarm/main.json b/avm/res/web/serverfarm/main.json index e6d8dd5be3..c339dd10ee 100644 --- a/avm/res/web/serverfarm/main.json +++ b/avm/res/web/serverfarm/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "489102920669919211" + "templateHash": "136819997431198276" }, "name": "App Service Plan", "description": "This module deploys an App Service Plan.", @@ -43,6 +43,13 @@ "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": { @@ -339,6 +346,13 @@ } }, "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')]", @@ -443,20 +457,20 @@ "appServicePlan_roleAssignments": { "copy": { "name": "appServicePlan_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Web/serverfarms', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Web/serverfarms', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "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')]" + "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": [ "appServicePlan" diff --git a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep index 7b0bd49b7c..374c5887ee 100644 --- a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep @@ -80,11 +80,13 @@ module testDeployment '../../../main.bicep' = [ } 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' diff --git a/avm/res/web/serverfarm/version.json b/avm/res/web/serverfarm/version.json index daf1a794d9..76049e1c4a 100644 --- a/avm/res/web/serverfarm/version.json +++ b/avm/res/web/serverfarm/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.2", + "version": "0.3", "pathFilters": [ "./main.json" ] -} +} \ No newline at end of file From f44015a552cf319d1cc82c160e5000dede97f42b Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 15 Oct 2024 00:51:52 +0200 Subject: [PATCH 87/93] feat: Updated CognitiveServices PE implementation to latest schema (#3521) ## Description - Updated PE implementation to latest schema ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Falsehr%2FcognitiveServicesPEImplementation&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/res/cognitive-services/account/README.md | 257 +++++++++++++----- avm/res/cognitive-services/account/main.bicep | 35 ++- avm/res/cognitive-services/account/main.json | 214 +++++++++++---- .../main.test.bicep | 15 +- .../account/tests/e2e/max/main.test.bicep | 20 +- .../tests/e2e/openai-private/main.test.bicep | 11 +- .../account/tests/e2e/speech/main.test.bicep | 10 +- .../tests/e2e/waf-aligned/main.test.bicep | 10 +- .../cognitive-services/account/version.json | 2 +- 9 files changed, 428 insertions(+), 146 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index a2c4698c2e..c4316e2e52 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -78,10 +78,16 @@ module account 'br/public:avm/res/cognitive-services/account:' = { location: '' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -135,10 +141,16 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "", - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + }, + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "" } ] @@ -182,10 +194,16 @@ param deployments = [ param location = '' param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -553,9 +571,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } ] - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -564,9 +586,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -701,9 +727,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } ], - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -712,9 +742,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } }, { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "" } ] @@ -839,9 +873,13 @@ param privateEndpoints = [ } } ] - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -850,9 +888,13 @@ param privateEndpoints = [ } } { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -922,9 +964,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { location: '' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -978,9 +1024,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "" } ] @@ -1024,9 +1074,13 @@ param deployments = [ param location = '' param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -1063,9 +1117,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -1121,9 +1179,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1171,9 +1233,13 @@ param managedIdentities = { } param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -1456,9 +1522,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -1527,9 +1597,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1586,9 +1660,13 @@ param managedIdentities = { } param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -2150,8 +2228,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`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. | -| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | -| [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`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. | @@ -2335,19 +2412,64 @@ The name of the private endpoint. - Required: No - Type: string -### Parameter: `privateEndpoints.privateDnsZoneGroupName` +### Parameter: `privateEndpoints.privateDnsZoneGroup` -The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. +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.privateDnsZoneResourceIds` +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` -The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. +The name of the private DNS zone group config. - Required: No -- Type: array +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string ### Parameter: `privateEndpoints.privateLinkServiceConnectionName` @@ -2379,7 +2501,7 @@ Array of role assignments to create. - `'Owner'` - `'Private DNS Zone Contributor'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` **Required parameters** @@ -2549,7 +2671,7 @@ Array of role assignments to create. - `'Contributor'` - `'Owner'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` - `'User Access Administrator'` **Required parameters** @@ -2736,6 +2858,7 @@ The storage accounts for this resource. | `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 cognitive services account. | +| `privateEndpoints` | array | The private endpoints of the congitive services account. | | `resourceGroupName` | string | The resource group the cognitive services account was deployed into. | | `resourceId` | string | The resource ID of the cognitive services account. | | `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | @@ -2746,7 +2869,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.6.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.8.0` | Remote reference | ## Data Collection diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 8dbadcfb78..e7d426a344 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -241,7 +241,7 @@ 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 (Preview)': subscriptionResourceId( + 'Role Based Access Control Administrator': subscriptionResourceId( 'Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' ) @@ -403,7 +403,7 @@ resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSetti } ] -module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.6.1' = [ +module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.8.0' = [ for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}' scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') @@ -444,8 +444,7 @@ module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endp 'Full' ).location lock: privateEndpoint.?lock ?? lock - privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName - privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags customDnsConfigs: privateEndpoint.?customDnsConfigs @@ -528,6 +527,17 @@ output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) : {} +@description('The private endpoints of the congitive services account.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: cognitiveService_privateEndpoints[i].outputs.name + resourceId: cognitiveService_privateEndpoints[i].outputs.resourceId + groupId: cognitiveService_privateEndpoints[i].outputs.groupId + customDnsConfig: cognitiveService_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: cognitiveService_privateEndpoints[i].outputs.networkInterfaceIds + } +] + // ================ // // Definitions // // ================ // @@ -618,11 +628,20 @@ type privateEndpointType = { @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string - @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') - privateDnsZoneGroupName: 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('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') - privateDnsZoneResourceIds: 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? diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index b1c8468f51..c2ce82cbd8 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "4946778004284930976" + "templateHash": "11788701359615687264" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -245,21 +245,44 @@ "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" + "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 groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, "isManualConnection": { @@ -887,7 +910,7 @@ "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')]", + "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')]" } }, @@ -1100,11 +1123,8 @@ "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')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, "roleAssignments": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" @@ -1133,13 +1153,34 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "13720311665093076615" + "templateHash": "10193943972635711937" }, "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": { @@ -1391,6 +1432,29 @@ } }, "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": { @@ -1426,18 +1490,11 @@ "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", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "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 private DNS zone group to configure for the private endpoint." } }, "location": { @@ -1510,7 +1567,7 @@ "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')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -1518,7 +1575,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.6.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1597,7 +1654,7 @@ ] }, "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", @@ -1608,28 +1665,52 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + "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": "15263454436186512874" + "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", @@ -1637,12 +1718,15 @@ "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "privateDNSResourceIds": { + "privateDnsZoneConfigs": { "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, "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." + "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": { @@ -1656,27 +1740,36 @@ "variables": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" } } } ] }, - "resources": [ - { + "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('privateDnsZoneConfigs')]" - } + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] } - ], + }, "outputs": { "name": { "type": "string", @@ -1743,6 +1836,13 @@ }, "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": { @@ -1948,6 +2048,22 @@ "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())]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } } } } \ No newline at end of file diff --git a/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep index fda05f65f1..2c500d20a3 100644 --- a/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep @@ -41,7 +41,6 @@ module nestedDependencies 'dependencies.bicep' = { } } - // ============== // // Test Execution // // ============== // @@ -72,10 +71,16 @@ module testDeployment '../../../main.bicep' = [ publicNetworkAccess: 'Disabled' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - nestedDependencies.outputs.privateDNSZoneOpenAIResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneOpenAIResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] diff --git a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep index 86f9529a0f..80c3f084d2 100644 --- a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep @@ -140,9 +140,13 @@ module testDeployment '../../../main.bicep' = [ } privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' @@ -169,9 +173,13 @@ module testDeployment '../../../main.bicep' = [ ] } { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] diff --git a/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep index 046f81ead1..ef683ee0aa 100644 --- a/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep @@ -41,7 +41,6 @@ module nestedDependencies 'dependencies.bicep' = { } } - // ============== // // Test Execution // // ============== // @@ -72,9 +71,13 @@ module testDeployment '../../../main.bicep' = [ publicNetworkAccess: 'Disabled' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] diff --git a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep index a4c8eb799b..776dfdad0e 100644 --- a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep @@ -56,9 +56,13 @@ module testDeployment '../../../main.bicep' = [ customSubDomainName: '${namePrefix}speechdomain' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep index 53649ec3f4..70f18da307 100644 --- a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep @@ -83,9 +83,13 @@ module testDeployment '../../../main.bicep' = [ sku: 'S0' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/avm/res/cognitive-services/account/version.json b/avm/res/cognitive-services/account/version.json index 7e1d3f4157..0f81d22abc 100644 --- a/avm/res/cognitive-services/account/version.json +++ b/avm/res/cognitive-services/account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.7", + "version": "0.8", "pathFilters": [ "./main.json" ] From 6074f327b25368f10201a6594c798f2d17d61ef1 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 15 Oct 2024 09:49:02 +0200 Subject: [PATCH 88/93] fix: Key Vault - Incorrect test value (#3398) ## Description Fixed incorrect test value in max test that was not reflecting the way the UDTs are implemented ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.key-vault.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FkvltParamFix&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/res/key-vault/vault/README.md | 36 ++++++++++++------- .../key-vault/vault/access-policy/main.json | 4 +-- avm/res/key-vault/vault/key/main.json | 4 +-- avm/res/key-vault/vault/secret/main.json | 4 +-- .../vault/tests/e2e/max/main.test.bicep | 12 ++++--- 5 files changed, 38 insertions(+), 22 deletions(-) diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 880c933a5f..1155d01736 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -352,8 +352,10 @@ module vault 'br/public:avm/res/key-vault/vault:' = { enableRbacAuthorization: false keys: [ { - attributesExp: 1725109032 - attributesNbf: 10000 + attributes: { + exp: 1725109032 + nbf: 10000 + } name: 'keyName' roleAssignments: [ { @@ -495,8 +497,10 @@ module vault 'br/public:avm/res/key-vault/vault:' = { ] secrets: [ { - attributesExp: 1702648632 - attributesNbf: 10000 + attributes: { + exp: 1725109032 + nbf: 10000 + } contentType: 'Something' name: 'secretName' roleAssignments: [ @@ -608,8 +612,10 @@ module vault 'br/public:avm/res/key-vault/vault:' = { "keys": { "value": [ { - "attributesExp": 1725109032, - "attributesNbf": 10000, + "attributes": { + "exp": 1725109032, + "nbf": 10000 + }, "name": "keyName", "roleAssignments": [ { @@ -763,8 +769,10 @@ module vault 'br/public:avm/res/key-vault/vault:' = { "secrets": { "value": [ { - "attributesExp": 1702648632, - "attributesNbf": 10000, + "attributes": { + "exp": 1725109032, + "nbf": 10000 + }, "contentType": "Something", "name": "secretName", "roleAssignments": [ @@ -870,8 +878,10 @@ param enablePurgeProtection = false param enableRbacAuthorization = false param keys = [ { - attributesExp: 1725109032 - attributesNbf: 10000 + attributes: { + exp: 1725109032 + nbf: 10000 + } name: 'keyName' roleAssignments: [ { @@ -1013,8 +1023,10 @@ param roleAssignments = [ ] param secrets = [ { - attributesExp: 1702648632 - attributesNbf: 10000 + attributes: { + exp: 1725109032 + nbf: 10000 + } contentType: 'Something' name: 'secretName' roleAssignments: [ diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index ba6a0ab33f..fcfca42035 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7494731697751039419" + "version": "0.30.23.60470", + "templateHash": "15469258025112973480" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 6976827555..981d9bad38 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.3.12046", - "templateHash": "13039550242026782790" + "version": "0.30.23.60470", + "templateHash": "796741209006922272" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index b516966b2f..8564674f8e 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "114626909766354577" + "version": "0.30.23.60470", + "templateHash": "10121697157844029321" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", diff --git a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep index 08693fdd86..c41f995bb5 100644 --- a/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/max/main.test.bicep @@ -123,8 +123,10 @@ module testDeployment '../../../main.bicep' = [ enableRbacAuthorization: false keys: [ { - attributesExp: 1725109032 - attributesNbf: 10000 + attributes: { + exp: 1725109032 + nbf: 10000 + } name: 'keyName' roleAssignments: [ { @@ -274,8 +276,10 @@ module testDeployment '../../../main.bicep' = [ ] secrets: [ { - attributesExp: 1702648632 - attributesNbf: 10000 + attributes: { + exp: 1725109032 + nbf: 10000 + } contentType: 'Something' name: 'secretName' roleAssignments: [ From f85062550a0129c69042deb80f3f056781173406 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 15 Oct 2024 10:26:38 +0200 Subject: [PATCH 89/93] fix: Databricks - Aligned PE test with latest schema (#3399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …be pulled into readme ## Description - Aligned PE test with latest schema - Aligned code slightly to allow roles to be pulled into readme ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.databricks.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml/badge.svg?branch=users%2Falsehr%2FdatabricksPEFix&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/res/databricks/workspace/README.md | 50 +++++++++++++++---- avm/res/databricks/workspace/main.bicep | 12 ++--- avm/res/databricks/workspace/main.json | 18 +++---- .../tests/e2e/waf-aligned/main.test.bicep | 10 ++-- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index 927dca6a7e..d16c2e43c4 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -584,9 +584,13 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { prepareEncryption: true privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } service: 'databricks_ui_api' subnetResourceId: '' tags: { @@ -724,9 +728,13 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "service": "databricks_ui_api", "subnetResourceId": "", "tags": { @@ -850,9 +858,13 @@ param natGatewayName = 'nat-gateway' param prepareEncryption = true param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } service: 'databricks_ui_api' subnetResourceId: '' tags: { @@ -1635,6 +1647,17 @@ 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** @@ -2221,10 +2244,15 @@ Array of role assignments to create. - 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'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** diff --git a/avm/res/databricks/workspace/main.bicep b/avm/res/databricks/workspace/main.bicep index 38f9840878..3db8d2c9b6 100644 --- a/avm/res/databricks/workspace/main.bicep +++ b/avm/res/databricks/workspace/main.bicep @@ -455,7 +455,7 @@ var _storageAccountId = resourceId( ) @batchSize(1) -module storageAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ +module storageAccount_storageAccountPrivateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ for (privateEndpoint, index) in (storageAccountPrivateEndpoints ?? []): if (privateStorageAccount == 'Enabled') { name: '${uniqueString(deployment().name, location)}-workspacestorage-PrivateEndpoint-${index}' scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') @@ -553,11 +553,11 @@ output storagePrivateEndpoints array = [ for (pe, i) in ((!empty(storageAccountPrivateEndpoints) && privateStorageAccount == 'Enabled') ? array(storageAccountPrivateEndpoints) : []): { - name: storageAccount_privateEndpoints[i].outputs.name - resourceId: storageAccount_privateEndpoints[i].outputs.resourceId - groupId: storageAccount_privateEndpoints[i].outputs.groupId - customDnsConfig: storageAccount_privateEndpoints[i].outputs.customDnsConfig - networkInterfaceIds: storageAccount_privateEndpoints[i].outputs.networkInterfaceIds + name: storageAccount_storageAccountPrivateEndpoints[i].outputs.name + resourceId: storageAccount_storageAccountPrivateEndpoints[i].outputs.resourceId + groupId: storageAccount_storageAccountPrivateEndpoints[i].outputs.groupId + customDnsConfig: storageAccount_storageAccountPrivateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: storageAccount_storageAccountPrivateEndpoints[i].outputs.networkInterfaceIds } ] diff --git a/avm/res/databricks/workspace/main.json b/avm/res/databricks/workspace/main.json index 2f4f7b5b64..e5ddd83cb3 100644 --- a/avm/res/databricks/workspace/main.json +++ b/avm/res/databricks/workspace/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8011778884263076951" + "version": "0.30.23.60470", + "templateHash": "7919315590916710106" }, "name": "Azure Databricks Workspaces", "description": "This module deploys an Azure Databricks Workspace.", @@ -1678,9 +1678,9 @@ "workspace" ] }, - "storageAccount_privateEndpoints": { + "storageAccount_storageAccountPrivateEndpoints": { "copy": { - "name": "storageAccount_privateEndpoints", + "name": "storageAccount_storageAccountPrivateEndpoints", "count": "[length(coalesce(parameters('storageAccountPrivateEndpoints'), createArray()))]", "mode": "serial", "batchSize": 1 @@ -2543,11 +2543,11 @@ "copy": { "count": "[length(if(and(not(empty(parameters('storageAccountPrivateEndpoints'))), equals(parameters('privateStorageAccount'), 'Enabled')), array(parameters('storageAccountPrivateEndpoints')), createArray()))]", "input": { - "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", - "customDnsConfig": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", - "networkInterfaceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + "name": "[reference(format('storageAccount_storageAccountPrivateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_storageAccountPrivateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('storageAccount_storageAccountPrivateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('storageAccount_storageAccountPrivateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('storageAccount_storageAccountPrivateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" } } } diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index 1602f41f85..b058538745 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -137,9 +137,13 @@ module testDeployment '../../../main.bicep' = [ customVirtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } service: 'databricks_ui_api' subnetResourceId: nestedDependencies.outputs.defaultSubnetResourceId tags: { From 0b236a57f245de292e1a2c6f003e9882ec580a0c Mon Sep 17 00:00:00 2001 From: Clint Grove Date: Tue, 15 Oct 2024 11:47:07 +0300 Subject: [PATCH 90/93] feat: Add security compliance options for `avm/res/databricks/workspace` (#3550) ## Description Added options to enable Security and Compliance for databricks workspaces. ### *EnhancedSecurityComplianceDefinition* Name | Description | Value -- | -- | -- automaticClusterUpdate | Status of automated cluster updates feature. | AutomaticClusterUpdateDefinition complianceSecurityProfile | Status of Compliance Security Profile feature. | ComplianceSecurityProfileDefinition enhancedSecurityMonitoring | Status of Enhanced Security Monitoring feature. | EnhancedSecurityMonitoringDefinition ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.databricks.workspace](https://github.com/clintgrove/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml/badge.svg?branch=3515-addSecurityComplianc)](https://github.com/clintgrove/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [x] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings Name Description Value automaticClusterUpdate Status of automated cluster updates feature. [AutomaticClusterUpdateDefinition](https://learn.microsoft.com/en-us/azure/templates/microsoft.databricks/workspaces?pivots=deployment-language-bicep#automaticclusterupdatedefinition) complianceSecurityProfile Status of Compliance Security Profile feature. [ComplianceSecurityProfileDefinition](https://learn.microsoft.com/en-us/azure/templates/microsoft.databricks/workspaces?pivots=deployment-language-bicep#compliancesecurityprofiledefinition) enhancedSecurityMonitoring Status of Enhanced Security Monitoring feature. [EnhancedSecurityMonitoringDefinition](https://learn.microsoft.com/en-us/azure/templates/microsoft.databricks/workspaces?pivots=deployment-language-bicep#enhancedsecuritymonitoringdefinition) --- avm/res/databricks/workspace/README.md | 104 ++++++++++++++++++ avm/res/databricks/workspace/main.bicep | 43 ++++++++ avm/res/databricks/workspace/main.json | 47 +++++++- .../workspace/tests/e2e/max/main.test.bicep | 4 + .../tests/e2e/waf-aligned/main.test.bicep | 3 + 5 files changed, 199 insertions(+), 2 deletions(-) diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index d16c2e43c4..1514771878 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -116,6 +116,12 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { name: 'dwmax002' // Non-required parameters amlWorkspaceResourceId: '' + automaticClusterUpdate: 'Enabled' + complianceSecurityProfileValue: 'Enabled' + complianceStandards: [ + 'HIPAA' + 'PCI_DSS' + ] customerManagedKey: { keyName: '' keyVaultResourceId: '' @@ -149,6 +155,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { } ] disablePublicIp: true + enhancedSecurityMonitoring: 'Enabled' loadBalancerBackendPoolName: '' loadBalancerResourceId: '' location: '' @@ -243,6 +250,18 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "amlWorkspaceResourceId": { "value": "" }, + "automaticClusterUpdate": { + "value": "Enabled" + }, + "complianceSecurityProfileValue": { + "value": "Enabled" + }, + "complianceStandards": { + "value": [ + "HIPAA", + "PCI_DSS" + ] + }, "customerManagedKey": { "value": { "keyName": "", @@ -292,6 +311,9 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "disablePublicIp": { "value": true }, + "enhancedSecurityMonitoring": { + "value": "Enabled" + }, "loadBalancerBackendPoolName": { "value": "" }, @@ -416,6 +438,12 @@ using 'br/public:avm/res/databricks/workspace:' param name = 'dwmax002' // Non-required parameters param amlWorkspaceResourceId = '' +param automaticClusterUpdate = 'Enabled' +param complianceSecurityProfileValue = 'Enabled' +param complianceStandards = [ + 'HIPAA' + 'PCI_DSS' +] param customerManagedKey = { keyName: '' keyVaultResourceId: '' @@ -449,6 +477,7 @@ param diagnosticSettings = [ } ] param disablePublicIp = true +param enhancedSecurityMonitoring = 'Enabled' param loadBalancerBackendPoolName = '' param loadBalancerResourceId = '' param location = '' @@ -542,6 +571,8 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { // Non-required parameters accessConnectorResourceId: '' amlWorkspaceResourceId: '' + automaticClusterUpdate: 'Enabled' + complianceSecurityProfileValue: 'Disabled' customerManagedKey: { keyName: '' keyVaultResourceId: '' @@ -572,6 +603,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { } ] disablePublicIp: true + enhancedSecurityMonitoring: 'Enabled' loadBalancerBackendPoolName: '' loadBalancerResourceId: '' location: '' @@ -657,6 +689,12 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "amlWorkspaceResourceId": { "value": "" }, + "automaticClusterUpdate": { + "value": "Enabled" + }, + "complianceSecurityProfileValue": { + "value": "Disabled" + }, "customerManagedKey": { "value": { "keyName": "", @@ -701,6 +739,9 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "disablePublicIp": { "value": true }, + "enhancedSecurityMonitoring": { + "value": "Enabled" + }, "loadBalancerBackendPoolName": { "value": "" }, @@ -816,6 +857,8 @@ param name = 'dwwaf001' // Non-required parameters param accessConnectorResourceId = '' param amlWorkspaceResourceId = '' +param automaticClusterUpdate = 'Enabled' +param complianceSecurityProfileValue = 'Disabled' param customerManagedKey = { keyName: '' keyVaultResourceId: '' @@ -846,6 +889,7 @@ param diagnosticSettings = [ } ] param disablePublicIp = true +param enhancedSecurityMonitoring = 'Enabled' param loadBalancerBackendPoolName = '' param loadBalancerResourceId = '' param location = '' @@ -928,6 +972,9 @@ param vnetAddressPrefix = '10.100' | Parameter | Type | Description | | :-- | :-- | :-- | | [`amlWorkspaceResourceId`](#parameter-amlworkspaceresourceid) | string | The resource ID of a Azure Machine Learning workspace to link with Databricks workspace. | +| [`automaticClusterUpdate`](#parameter-automaticclusterupdate) | string | The value for enabling automatic cluster updates in enhanced security compliance. | +| [`complianceSecurityProfileValue`](#parameter-compliancesecurityprofilevalue) | string | The value to Enable or Disable for the compliance security profile. | +| [`complianceStandards`](#parameter-compliancestandards) | array | The compliance standards array for the security profile. Should be a list of compliance standards like "HIPAA", "NONE" or "PCI_DSS". | | [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition to use for the managed service. | | [`customerManagedKeyManagedDisk`](#parameter-customermanagedkeymanageddisk) | object | The customer managed key definition to use for the managed disk. | | [`customPrivateSubnetName`](#parameter-customprivatesubnetname) | string | The name of the Private Subnet within the Virtual Network. | @@ -937,6 +984,7 @@ param vnetAddressPrefix = '10.100' | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`disablePublicIp`](#parameter-disablepublicip) | bool | Disable Public IP. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`enhancedSecurityMonitoring`](#parameter-enhancedsecuritymonitoring) | string | The value for enabling or configuring enhanced security monitoring. | | [`loadBalancerBackendPoolName`](#parameter-loadbalancerbackendpoolname) | string | Name of the outbound Load Balancer Backend Pool for Secure Cluster Connectivity (No Public IP). | | [`loadBalancerResourceId`](#parameter-loadbalancerresourceid) | string | Resource URI of Outbound Load balancer for Secure Cluster Connectivity (No Public IP) workspace. | | [`location`](#parameter-location) | string | Location for all Resources. | @@ -981,6 +1029,46 @@ The resource ID of a Azure Machine Learning workspace to link with Databricks wo - Type: string - Default: `''` +### Parameter: `automaticClusterUpdate` + +The value for enabling automatic cluster updates in enhanced security compliance. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `complianceSecurityProfileValue` + +The value to Enable or Disable for the compliance security profile. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `complianceStandards` + +The compliance standards array for the security profile. Should be a list of compliance standards like "HIPAA", "NONE" or "PCI_DSS". + +- Required: No +- Type: array +- Default: `[]` + ### Parameter: `customerManagedKey` The customer managed key definition to use for the managed service. @@ -1266,6 +1354,22 @@ Enable/Disable usage telemetry for module. - Type: bool - Default: `True` +### Parameter: `enhancedSecurityMonitoring` + +The value for enabling or configuring enhanced security monitoring. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + ### Parameter: `loadBalancerBackendPoolName` Name of the outbound Load Balancer Backend Pool for Secure Cluster Connectivity (No Public IP). diff --git a/avm/res/databricks/workspace/main.bicep b/avm/res/databricks/workspace/main.bicep index 3db8d2c9b6..5f3d0e7cdc 100644 --- a/avm/res/databricks/workspace/main.bicep +++ b/avm/res/databricks/workspace/main.bicep @@ -116,6 +116,33 @@ param accessConnectorResourceId string = '' @description('Optional. The default catalog configuration for the Databricks workspace.') param defaultCatalog defaultCatalogType? +@description('Optional. The value for enabling automatic cluster updates in enhanced security compliance.') +@allowed([ + 'Enabled' + 'Disabled' + '' +]) +param automaticClusterUpdate string = '' + +@description('Optional. The compliance standards array for the security profile. Should be a list of compliance standards like "HIPAA", "NONE" or "PCI_DSS".') +param complianceStandards array = [] + +@description('Optional. The value to Enable or Disable for the compliance security profile.') +@allowed([ + 'Enabled' + 'Disabled' + '' +]) +param complianceSecurityProfileValue string = '' + +@description('Optional. The value for enabling or configuring enhanced security monitoring.') +@allowed([ + 'Enabled' + 'Disabled' + '' +]) +param enhancedSecurityMonitoring string = '' + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -339,6 +366,22 @@ resource workspace 'Microsoft.Databricks/workspaces@2024-05-01' = { initialType: defaultCatalog.?initialType } } + : {}, + !empty(automaticClusterUpdate) || !empty(complianceStandards) || !empty(enhancedSecurityMonitoring) + ? { + enhancedSecurityCompliance: { + automaticClusterUpdate: { + value: automaticClusterUpdate + } + complianceSecurityProfile: { + complianceStandards: complianceStandards + value: complianceSecurityProfileValue + } + enhancedSecurityMonitoring: { + value: enhancedSecurityMonitoring + } + } + } : {} ) } diff --git a/avm/res/databricks/workspace/main.json b/avm/res/databricks/workspace/main.json index e5ddd83cb3..7d47a2361c 100644 --- a/avm/res/databricks/workspace/main.json +++ b/avm/res/databricks/workspace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "7919315590916710106" + "templateHash": "3097369557346474015" }, "name": "Azure Databricks Workspaces", "description": "This module deploys an Azure Databricks Workspace.", @@ -746,6 +746,49 @@ "metadata": { "description": "Optional. The default catalog configuration for the Databricks workspace." } + }, + "automaticClusterUpdate": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Enabled", + "Disabled", + "" + ], + "metadata": { + "description": "Optional. The value for enabling automatic cluster updates in enhanced security compliance." + } + }, + "complianceStandards": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The compliance standards array for the security profile. Should be a list of compliance standards like \"HIPAA\", \"NONE\" or \"PCI_DSS\"." + } + }, + "complianceSecurityProfileValue": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Enabled", + "Disabled", + "" + ], + "metadata": { + "description": "Optional. The value to Enable or Disable for the compliance security profile." + } + }, + "enhancedSecurityMonitoring": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Enabled", + "Disabled", + "" + ], + "metadata": { + "description": "Optional. The value for enabling or configuring enhanced security monitoring." + } } }, "variables": { @@ -836,7 +879,7 @@ "sku": { "name": "[parameters('skuName')]" }, - "properties": "[union(createObject('managedResourceGroupId', if(not(empty(parameters('managedResourceGroupResourceId'))), parameters('managedResourceGroupResourceId'), format('{0}/resourceGroups/rg-{1}-managed', subscription().id, parameters('name'))), 'parameters', union(createObject('enableNoPublicIp', createObject('value', parameters('disablePublicIp')), 'prepareEncryption', createObject('value', parameters('prepareEncryption')), 'vnetAddressPrefix', createObject('value', parameters('vnetAddressPrefix')), 'requireInfrastructureEncryption', createObject('value', parameters('requireInfrastructureEncryption'))), if(not(empty(parameters('customVirtualNetworkResourceId'))), createObject('customVirtualNetworkId', createObject('value', parameters('customVirtualNetworkResourceId'))), createObject()), if(not(empty(parameters('amlWorkspaceResourceId'))), createObject('amlWorkspaceId', createObject('value', parameters('amlWorkspaceResourceId'))), createObject()), if(not(empty(parameters('customPrivateSubnetName'))), createObject('customPrivateSubnetName', createObject('value', parameters('customPrivateSubnetName'))), createObject()), if(not(empty(parameters('customPublicSubnetName'))), createObject('customPublicSubnetName', createObject('value', parameters('customPublicSubnetName'))), createObject()), if(not(empty(parameters('loadBalancerBackendPoolName'))), createObject('loadBalancerBackendPoolName', createObject('value', parameters('loadBalancerBackendPoolName'))), createObject()), if(not(empty(parameters('loadBalancerResourceId'))), createObject('loadBalancerId', createObject('value', parameters('loadBalancerResourceId'))), createObject()), if(not(empty(parameters('natGatewayName'))), createObject('natGatewayName', createObject('value', parameters('natGatewayName'))), createObject()), if(not(empty(parameters('publicIpName'))), createObject('publicIpName', createObject('value', parameters('publicIpName'))), createObject()), if(not(empty(parameters('storageAccountName'))), createObject('storageAccountName', createObject('value', parameters('storageAccountName'))), createObject()), if(not(empty(parameters('storageAccountSkuName'))), createObject('storageAccountSkuName', createObject('value', parameters('storageAccountSkuName'))), createObject())), 'publicNetworkAccess', parameters('publicNetworkAccess'), 'requiredNsgRules', parameters('requiredNsgRules'), 'encryption', if(or(not(empty(parameters('customerManagedKey'))), not(empty(parameters('customerManagedKeyManagedDisk')))), createObject('entities', createObject('managedServices', if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.Keyvault', 'keyVaultProperties', createObject('keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null()), 'managedDisk', if(not(empty(parameters('customerManagedKeyManagedDisk'))), createObject('keySource', 'Microsoft.Keyvault', 'keyVaultProperties', createObject('keyVaultUri', reference('cMKManagedDiskKeyVault').vaultUri, 'keyName', parameters('customerManagedKeyManagedDisk').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVersion'), ''))), parameters('customerManagedKeyManagedDisk').keyVersion, last(split(reference('cMKManagedDiskKeyVault::cMKKey').keyUriWithVersion, '/')))), 'rotationToLatestKeyVersionEnabled', coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'rotationToLatestKeyVersionEnabled'), true())), null()))), null())), if(not(empty(parameters('privateStorageAccount'))), createObject('defaultStorageFirewall', parameters('privateStorageAccount'), 'accessConnector', createObject('id', parameters('accessConnectorResourceId'), 'identityType', 'SystemAssigned')), createObject()), if(not(empty(parameters('defaultCatalog'))), createObject('defaultCatalog', createObject('initialName', '', 'initialType', tryGet(parameters('defaultCatalog'), 'initialType'))), createObject()))]", + "properties": "[union(createObject('managedResourceGroupId', if(not(empty(parameters('managedResourceGroupResourceId'))), parameters('managedResourceGroupResourceId'), format('{0}/resourceGroups/rg-{1}-managed', subscription().id, parameters('name'))), 'parameters', union(createObject('enableNoPublicIp', createObject('value', parameters('disablePublicIp')), 'prepareEncryption', createObject('value', parameters('prepareEncryption')), 'vnetAddressPrefix', createObject('value', parameters('vnetAddressPrefix')), 'requireInfrastructureEncryption', createObject('value', parameters('requireInfrastructureEncryption'))), if(not(empty(parameters('customVirtualNetworkResourceId'))), createObject('customVirtualNetworkId', createObject('value', parameters('customVirtualNetworkResourceId'))), createObject()), if(not(empty(parameters('amlWorkspaceResourceId'))), createObject('amlWorkspaceId', createObject('value', parameters('amlWorkspaceResourceId'))), createObject()), if(not(empty(parameters('customPrivateSubnetName'))), createObject('customPrivateSubnetName', createObject('value', parameters('customPrivateSubnetName'))), createObject()), if(not(empty(parameters('customPublicSubnetName'))), createObject('customPublicSubnetName', createObject('value', parameters('customPublicSubnetName'))), createObject()), if(not(empty(parameters('loadBalancerBackendPoolName'))), createObject('loadBalancerBackendPoolName', createObject('value', parameters('loadBalancerBackendPoolName'))), createObject()), if(not(empty(parameters('loadBalancerResourceId'))), createObject('loadBalancerId', createObject('value', parameters('loadBalancerResourceId'))), createObject()), if(not(empty(parameters('natGatewayName'))), createObject('natGatewayName', createObject('value', parameters('natGatewayName'))), createObject()), if(not(empty(parameters('publicIpName'))), createObject('publicIpName', createObject('value', parameters('publicIpName'))), createObject()), if(not(empty(parameters('storageAccountName'))), createObject('storageAccountName', createObject('value', parameters('storageAccountName'))), createObject()), if(not(empty(parameters('storageAccountSkuName'))), createObject('storageAccountSkuName', createObject('value', parameters('storageAccountSkuName'))), createObject())), 'publicNetworkAccess', parameters('publicNetworkAccess'), 'requiredNsgRules', parameters('requiredNsgRules'), 'encryption', if(or(not(empty(parameters('customerManagedKey'))), not(empty(parameters('customerManagedKeyManagedDisk')))), createObject('entities', createObject('managedServices', if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.Keyvault', 'keyVaultProperties', createObject('keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null()), 'managedDisk', if(not(empty(parameters('customerManagedKeyManagedDisk'))), createObject('keySource', 'Microsoft.Keyvault', 'keyVaultProperties', createObject('keyVaultUri', reference('cMKManagedDiskKeyVault').vaultUri, 'keyName', parameters('customerManagedKeyManagedDisk').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVersion'), ''))), parameters('customerManagedKeyManagedDisk').keyVersion, last(split(reference('cMKManagedDiskKeyVault::cMKKey').keyUriWithVersion, '/')))), 'rotationToLatestKeyVersionEnabled', coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'rotationToLatestKeyVersionEnabled'), true())), null()))), null())), if(not(empty(parameters('privateStorageAccount'))), createObject('defaultStorageFirewall', parameters('privateStorageAccount'), 'accessConnector', createObject('id', parameters('accessConnectorResourceId'), 'identityType', 'SystemAssigned')), createObject()), if(not(empty(parameters('defaultCatalog'))), createObject('defaultCatalog', createObject('initialName', '', 'initialType', tryGet(parameters('defaultCatalog'), 'initialType'))), createObject()), if(or(or(not(empty(parameters('automaticClusterUpdate'))), not(empty(parameters('complianceStandards')))), not(empty(parameters('enhancedSecurityMonitoring')))), createObject('enhancedSecurityCompliance', createObject('automaticClusterUpdate', createObject('value', parameters('automaticClusterUpdate')), 'complianceSecurityProfile', createObject('complianceStandards', parameters('complianceStandards'), 'value', parameters('complianceSecurityProfileValue')), 'enhancedSecurityMonitoring', createObject('value', parameters('enhancedSecurityMonitoring')))), createObject()))]", "dependsOn": [ "cMKKeyVault", "cMKManagedDiskKeyVault" diff --git a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep index 3ee2aeb6e5..36c77b6310 100644 --- a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep @@ -192,6 +192,10 @@ module testDeployment '../../../main.bicep' = [ //initialName: '' Cannot be set to anything other than an empty string. {"code":"InvalidInitialCatalogName","message":"Currently custom initial catalog name is not supported. This capability will be added in future."} initialType: 'UnityCatalog' // Choose between 'HiveCatalog' OR 'UnityCatalog' } + complianceSecurityProfileValue: 'Enabled' // If this is set to 'Enabled', then the complianceStandards must be set to 'HIPAA', 'NONE' or 'PCI_DSS' and the enhancedSecurityMonitoring must be set to 'Enabled' as well as the automaticClusterUpdate + complianceStandards: ['HIPAA', 'PCI_DSS'] // Options are HIPAA, PCI_DSS or NONE. However NONE cannot be selected in addition to other compliance standards + enhancedSecurityMonitoring: 'Enabled' // This can be set to 'Enabled' without the complianceSecurityProfileValue being set to 'Enabled' + automaticClusterUpdate: 'Enabled' // This can be set to 'Enabled' without the complianceSecurityProfileValue being set to 'Enabled' } dependsOn: [ nestedDependencies diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index b058538745..25b757e1af 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -175,6 +175,9 @@ module testDeployment '../../../main.bicep' = [ } } ] + complianceSecurityProfileValue: 'Disabled' + enhancedSecurityMonitoring: 'Enabled' // This can be set to 'Enabled' without the complianceSecurityProfileValue being set to 'Enabled' + automaticClusterUpdate: 'Enabled' // This can be set to 'Enabled' without the complianceSecurityProfileValue being set to 'Enabled' } dependsOn: [ nestedDependencies From 55ee2c8c3a63ef0929d3372d3e6fc7a972a9d522 Mon Sep 17 00:00:00 2001 From: Seif Bassem <38246040+sebassem@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:04:57 +0300 Subject: [PATCH 91/93] fix: bump vnet version for sub-vending (#3561) ## Description Fixes #3386 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.lz.sub-vending](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml/badge.svg?branch=avm-lz-sub-vending-rbac-delegation)](https://github.com/sebassem/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/ptn/lz/sub-vending/README.md | 2 +- avm/ptn/lz/sub-vending/main.json | 52 ++++++++++--------- .../modules/subResourceWrapper.bicep | 4 +- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/avm/ptn/lz/sub-vending/README.md b/avm/ptn/lz/sub-vending/README.md index c5abe03e9f..4f765f003b 100644 --- a/avm/ptn/lz/sub-vending/README.md +++ b/avm/ptn/lz/sub-vending/README.md @@ -1088,7 +1088,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | `br/public:avm/ptn/authorization/role-assignment:0.1.0` | Remote reference | | `br/public:avm/res/managed-identity/user-assigned-identity:0.2.2` | Remote reference | | `br/public:avm/res/network/network-security-group:0.3.0` | Remote reference | -| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.1` | Remote reference | | `br/public:avm/res/resources/deployment-script:0.2.3` | Remote reference | | `br/public:avm/res/resources/resource-group:0.2.4` | Remote reference | | `br/public:avm/res/storage/storage-account:0.9.1` | Remote reference | diff --git a/avm/ptn/lz/sub-vending/main.json b/avm/ptn/lz/sub-vending/main.json index ee24f61ead..657cbd9f62 100644 --- a/avm/ptn/lz/sub-vending/main.json +++ b/avm/ptn/lz/sub-vending/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "2644636658214532574" + "templateHash": "15297648363887235052" }, "name": "Sub-vending", "description": "This module deploys a subscription to accelerate deployment of landing zones. For more information on how to use it, please visit this [Wiki](https://github.com/Azure/bicep-lz-vending/wiki).", @@ -663,7 +663,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "2549730186599602050" + "templateHash": "16600088245608261230" }, "name": "`/subResourcesWrapper/deploy.bicep` Parameters", "description": "This module is used by the [`bicep-lz-vending`](https://aka.ms/sub-vending/bicep) module to help orchestrate the deployment", @@ -2339,8 +2339,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15949466154563447171" + "version": "0.30.23.60470", + "templateHash": "5074972058800471543" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -2954,7 +2954,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -3138,8 +3138,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5699372618313647761" + "version": "0.30.23.60470", + "templateHash": "6677157161292207910" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -3517,8 +3517,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5206620163504251868" + "version": "0.30.23.60470", + "templateHash": "345394220621166229" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3623,7 +3623,8 @@ } }, "dependsOn": [ - "virtualNetwork" + "virtualNetwork", + "virtualNetwork_subnets" ] }, "virtualNetwork_peering_remote": { @@ -3674,8 +3675,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5206620163504251868" + "version": "0.30.23.60470", + "templateHash": "345394220621166229" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3780,7 +3781,8 @@ } }, "dependsOn": [ - "virtualNetwork" + "virtualNetwork", + "virtualNetwork_subnets" ] } }, @@ -13697,8 +13699,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15949466154563447171" + "version": "0.30.23.60470", + "templateHash": "5074972058800471543" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -14312,7 +14314,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -14496,8 +14498,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5699372618313647761" + "version": "0.30.23.60470", + "templateHash": "6677157161292207910" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -14875,8 +14877,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5206620163504251868" + "version": "0.30.23.60470", + "templateHash": "345394220621166229" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -14981,7 +14983,8 @@ } }, "dependsOn": [ - "virtualNetwork" + "virtualNetwork", + "virtualNetwork_subnets" ] }, "virtualNetwork_peering_remote": { @@ -15032,8 +15035,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5206620163504251868" + "version": "0.30.23.60470", + "templateHash": "345394220621166229" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -15138,7 +15141,8 @@ } }, "dependsOn": [ - "virtualNetwork" + "virtualNetwork", + "virtualNetwork_subnets" ] } }, diff --git a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep index d0b80795eb..ac4285c052 100644 --- a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep +++ b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep @@ -388,7 +388,7 @@ module tagResourceGroup 'tags.bicep' = if (virtualNetworkEnabled && !empty(virtu } } -module createLzVnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (virtualNetworkEnabled && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) { +module createLzVnet 'br/public:avm/res/network/virtual-network:0.4.1' = if (virtualNetworkEnabled && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) { dependsOn: [ createResourceGroupForLzNetworking ] @@ -579,7 +579,7 @@ module createDsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' } } -module createDsVnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (!empty(resourceProviders)) { +module createDsVnet 'br/public:avm/res/network/virtual-network:0.4.1' = if (!empty(resourceProviders)) { scope: resourceGroup(subscriptionId, deploymentScriptResourceGroupName) name: deploymentNames.createdsVnet params: { From 6fd1411c277b9ffd9f5b7c88f100ecacbb1bc788 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 15 Oct 2024 14:08:44 +0200 Subject: [PATCH 92/93] feat: Removed explicit 'latest' pwsh installation for `Set-EnvironmentOnAgent` script (#3559) ## Description - Removed explicit 'latest' pwsh installation for `Set-EnvironmentOnAgent` script - The original issue was rooted in an issue with pwsh version `7.2.9` which was fixed fast, but the version not updated on the agents for the longest time. Now, the pre-installed pwsh version is 7.4.*, rendering the installation redundant (and could actually lead to issues) ## Pipeline Reference | Pipeline | | -------- | [![avm.ptn.aca-lza.hosting-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.aca-lza.hosting-environment.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.aca-lza.hosting-environment.yml) [![avm.ptn.ai-platform.baseline](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml) [![avm.ptn.authorization.policy-assignment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml) [![avm.ptn.authorization.resource-role-assignment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml) [![avm.ptn.authorization.role-assignment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml) [![avm.ptn.azd.acr-container-app](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.acr-container-app.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.acr-container-app.yml) [![avm.ptn.azd.aks](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml) [![avm.ptn.azd.apim-api](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.apim-api.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.apim-api.yml) [![avm.ptn.azd.container-app-upsert](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-app-upsert.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-app-upsert.yml) [![avm.ptn.azd.container-apps-stack](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-apps-stack.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-apps-stack.yml) [![avm.ptn.azd.insights-dashboard](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.insights-dashboard.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.insights-dashboard.yml) [![avm.ptn.azd.ml-ai-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-ai-environment.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-ai-environment.yml) [![avm.ptn.azd.ml-hub-dependencies](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-hub-dependencies.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-hub-dependencies.yml) [![avm.ptn.azd.ml-project](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) [![avm.ptn.azd.monitoring](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.monitoring.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.monitoring.yml) [![avm.ptn.deployment-script.import-image-to-acr](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml) (unrelated WAF) [![avm.ptn.dev-ops.cicd-agents-and-runners](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.dev-ops.cicd-agents-and-runners.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.dev-ops.cicd-agents-and-runners.yml) [![avm.ptn.finops-toolkit.finops-hub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.finops-toolkit.finops-hub.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.finops-toolkit.finops-hub.yml) [![avm.ptn.lz.sub-vending](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml) [![avm.ptn.network.hub-networking](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.network.hub-networking.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.network.hub-networking.yml) (unrelated WAF) [![avm.ptn.network.private-link-private-dns-zones](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.network.private-link-private-dns-zones.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.network.private-link-private-dns-zones.yml) [![avm.ptn.policy-insights.remediation](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml) [![avm.ptn.security.security-center](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml) [![avm.ptn.virtual-machine-images.azure-image-builder](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml) [![avm.res.aad.domain-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml) [![avm.res.alerts-management.action-rule](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.alerts-management.action-rule.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.alerts-management.action-rule.yml) [![avm.res.analysis-services.server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml) [![avm.res.api-management.service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml) [![avm.res.app-configuration.configuration-store](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml) [![avm.res.app.container-app](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml) [![avm.res.app.job](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.job.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.job.yml) [![avm.res.app.managed-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml) [![avm.res.automation.automation-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml) [![avm.res.batch.batch-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml) [![avm.res.cache.redis](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml) [![avm.res.cdn.profile](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml) [![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) [![avm.res.communication.communication-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml) [![avm.res.communication.email-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml) [![avm.res.compute.availability-set](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml) [![avm.res.compute.disk-encryption-set](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml) [![avm.res.compute.disk](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml) [![avm.res.compute.gallery](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml) [![avm.res.compute.image](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml) [![avm.res.compute.proximity-placement-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml) [![avm.res.compute.ssh-public-key](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml) [![avm.res.compute.virtual-machine-scale-set](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml) [![avm.res.compute.virtual-machine](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml) [![avm.res.consumption.budget](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml) [![avm.res.container-instance.container-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml) [![avm.res.container-registry.registry](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml) [![avm.res.container-service.managed-cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml) [![avm.res.data-factory.factory](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml) [![avm.res.data-protection.backup-vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml) [![avm.res.databricks.access-connector](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml) [![avm.res.databricks.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml) [![avm.res.db-for-my-sql.flexible-server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml) [![avm.res.db-for-postgre-sql.flexible-server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml) [![avm.res.desktop-virtualization.application-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml) [![avm.res.desktop-virtualization.host-pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml) [![avm.res.desktop-virtualization.scaling-plan](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml) [![avm.res.desktop-virtualization.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml) [![avm.res.dev-ops-infrastructure.pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml) [![avm.res.dev-test-lab.lab](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml) (unrelated WAF + broken template) [![avm.res.digital-twins.digital-twins-instance](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml) [![avm.res.document-db.database-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml) [![avm.res.document-db.mongo-cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.mongo-cluster.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.mongo-cluster.yml) [![avm.res.event-grid.domain](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml) [![avm.res.event-grid.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml) [![avm.res.event-grid.system-topic](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml) [![avm.res.event-grid.topic](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml) [![avm.res.event-hub.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml) [![avm.res.fabric.capacity](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.fabric.capacity.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.fabric.capacity.yml) [![avm.res.health-bot.health-bot](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml) [![avm.res.healthcare-apis.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml) [![avm.res.hybrid-compute.machine](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.hybrid-compute.machine.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.hybrid-compute.machine.yml) [![avm.res.insights.action-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml) [![avm.res.insights.activity-log-alert](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml) [![avm.res.insights.component](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml) [![avm.res.insights.data-collection-endpoint](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml) [![avm.res.insights.data-collection-rule](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml) [![avm.res.insights.diagnostic-setting](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml) [![avm.res.insights.metric-alert](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml) [![avm.res.insights.private-link-scope](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml) [![avm.res.insights.scheduled-query-rule](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml) [![avm.res.insights.webtest](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml) [![avm.res.key-vault.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) [![avm.res.kubernetes-configuration.extension](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml) [![avm.res.kubernetes-configuration.flux-configuration](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml) [![avm.res.kusto.cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kusto.cluster.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kusto.cluster.yml) [![avm.res.load-test-service.load-test](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml) [![avm.res.logic.workflow](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml) [![avm.res.machine-learning-services.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml) [![avm.res.maintenance.maintenance-configuration](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml) [![avm.res.managed-identity.user-assigned-identity](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml) [![avm.res.managed-services.registration-definition](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml) [![avm.res.management.management-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml) [![avm.res.net-app.net-app-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml) [![avm.res.network.application-gateway-web-application-firewall-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml) [![avm.res.network.application-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml) [![avm.res.network.application-security-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml) [![avm.res.network.azure-firewall](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) [![avm.res.network.bastion-host](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml) [![avm.res.network.connection](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml) [![avm.res.network.ddos-protection-plan](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml) [![avm.res.network.dns-forwarding-ruleset](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml) [![avm.res.network.dns-resolver](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml) [![avm.res.network.dns-zone](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml) [![avm.res.network.express-route-circuit](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml) [![avm.res.network.express-route-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml) [![avm.res.network.firewall-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml) [![avm.res.network.front-door-web-application-firewall-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml) [![avm.res.network.front-door](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml) [![avm.res.network.ip-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml) [![avm.res.network.load-balancer](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml) [![avm.res.network.local-network-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml) [![avm.res.network.nat-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml) [![avm.res.network.network-interface](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml) [![avm.res.network.network-manager](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml) [![avm.res.network.network-security-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml) [![avm.res.network.network-watcher](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml) [![avm.res.network.private-dns-zone](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml) [![avm.res.network.private-endpoint](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml) [![avm.res.network.private-link-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml) [![avm.res.network.public-ip-address](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml) [![avm.res.network.public-ip-prefix](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml) [![avm.res.network.route-table](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml) [![avm.res.network.service-endpoint-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml) [![avm.res.network.trafficmanagerprofile](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml) [![avm.res.network.virtual-hub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml) [![avm.res.network.virtual-network-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml) [![avm.res.network.virtual-network](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) [![avm.res.network.virtual-wan](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml) [![avm.res.network.vpn-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml) [![avm.res.network.vpn-server-configuration](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-server-configuration.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-server-configuration.yml) [![avm.res.network.vpn-site](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml) [![avm.res.operational-insights.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml) [![avm.res.operations-management.solution](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml) [![avm.res.portal.dashboard](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.portal.dashboard.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.portal.dashboard.yml) [![avm.res.power-bi-dedicated.capacity](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml) [![avm.res.purview.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml) [![avm.res.recovery-services.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml) [![avm.res.relay.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml) [![avm.res.resource-graph.query](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml) [![avm.res.resources.deployment-script](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml) [![avm.res.resources.resource-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml) [![avm.res.search.search-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml) [![avm.res.service-bus.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml) [![avm.res.service-fabric.cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml) [![avm.res.service-networking.traffic-controller](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-networking.traffic-controller.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-networking.traffic-controller.yml) [![avm.res.signal-r-service.signal-r](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml) [![avm.res.signal-r-service.web-pub-sub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml) [![avm.res.sql.instance-pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml) [![avm.res.sql.managed-instance](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml) [![avm.res.sql.server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml) [![avm.res.storage.storage-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml) [![avm.res.synapse.private-link-hub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml) [![avm.res.synapse.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml) [![avm.res.virtual-machine-images.image-template](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml) [![avm.res.web.connection](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml) [![avm.res.web.hosting-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml) (unrelated WAF) [![avm.res.web.serverfarm](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml) [![avm.res.web.site](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.site.yml) [![avm.res.web.static-site](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml/badge.svg?branch=users%2Falsehr%2FtestPwshNonInstall&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml) ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .../sharedScripts/Set-EnvironmentOnAgent.ps1 | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 b/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 index bcfb7253ab..6823db5233 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-EnvironmentOnAgent.ps1 @@ -114,6 +114,9 @@ Optional. The PowerShell modules that should be installed on the agent. } ) +.PARAMETER InstallLatestPwshVersion +Optional. Enable to install the latest PowerShell version + .EXAMPLE Set-EnvironmentOnAgent @@ -133,7 +136,10 @@ function Set-EnvironmentOnAgent { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] - [Hashtable[]] $PSModules = @() + [Hashtable[]] $PSModules = @(), + + [Parameter(Mandatory = $false)] + [switch] $InstallLatestPwshVersion ) ############################ @@ -258,10 +264,12 @@ function Set-EnvironmentOnAgent { } Write-Verbose ('Install-CustomModule end') -Verbose +} - ##################################### - ## TEMP PowerShell installation ## - ##################################### +if ($InstallLatestPwshVersion) { + Write-Verbose '=======================' -Verbose + Write-Verbose 'PowerShell installation' -Verbose + Write-Verbose '=======================' -Verbose # Update the list of packages sudo apt-get update From da7e5cbbb34f912d7bb63ce74770cc29fb770445 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Tue, 15 Oct 2024 19:01:36 +0200 Subject: [PATCH 93/93] feat: New utility module - AVM Common Types (#3397) ## Description - Implemented AVM common types module which can be used to reduce duplicated code in the code base - Reduced the tests in `main.test.bicep` for UDTs as they are not compatible with using a module reference - Added a quotation-escape to the deployment action as it turned out that it breaks if you have single quotes in your deployment output Example implementation in KeyVault module: > **Note:** The type should always be implemented by name as a `*` implementation causes all types to be added to the combiled `main.json` ![image](https://github.com/user-attachments/assets/76837be7-121b-4a76-a2f8-89c924abbcd8) ![image](https://github.com/user-attachments/assets/10507e09-a289-4b9e-b97f-c6e8241cd3ca) ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.types.avm-common-type](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.utl.types.avm-common-type.yml/badge.svg?branch=users%2Falsehr%2F1396_commonTypes)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.utl.types.avm-common-type.yml) | | [![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2F1396_commonTypes)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml) [run using local ref](https://github.com/AlexanderSehr/bicep-registry-modules/actions/runs/11164377047) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm-validateModuleDeployment/action.yml | 2 +- .../avm.utl.types.avm-common-types.yml | 89 ++ .../compliance/module.tests.ps1 | 79 +- avm/utl/types/avm-common-types/README.md | 331 +++++++ avm/utl/types/avm-common-types/main.bicep | 404 ++++++++ avm/utl/types/avm-common-types/main.json | 934 ++++++++++++++++++ .../tests/e2e/import/main.test.bicep | 278 ++++++ avm/utl/types/avm-common-types/version.json | 7 + 10 files changed, 2053 insertions(+), 73 deletions(-) create mode 100644 .github/workflows/avm.utl.types.avm-common-types.yml create mode 100644 avm/utl/types/avm-common-types/README.md create mode 100644 avm/utl/types/avm-common-types/main.bicep create mode 100644 avm/utl/types/avm-common-types/main.json create mode 100644 avm/utl/types/avm-common-types/tests/e2e/import/main.test.bicep create mode 100644 avm/utl/types/avm-common-types/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 34070f3b2b..da1572ec12 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -171,4 +171,5 @@ /avm/res/web/serverfarm/ @Azure/avm-res-web-serverfarm-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/web/site/ @Azure/avm-res-web-site-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/web/static-site/ @Azure/avm-res-web-staticsite-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/utl/types/avm-common-types/ @Azure/avm-utl-types-avmcommontypes-module-owners-bicep @Azure/avm-module-reviewers-bicep *avm.core.team.tests.ps1 @Azure/avm-core-team-technical-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 56d3fb70d3..4914b3f21a 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -206,6 +206,7 @@ body: - "avm/res/web/serverfarm" - "avm/res/web/site" - "avm/res/web/static-site" + - "avm/utl/types/avm-common-types" validations: required: true - type: input diff --git a/.github/actions/templates/avm-validateModuleDeployment/action.yml b/.github/actions/templates/avm-validateModuleDeployment/action.yml index 715a2f642b..b272554729 100644 --- a/.github/actions/templates/avm-validateModuleDeployment/action.yml +++ b/.github/actions/templates/avm-validateModuleDeployment/action.yml @@ -327,7 +327,7 @@ runs: Write-Output ('{0}={1}' -f 'deploymentNames', ($res.deploymentNames | ConvertTo-Json -Compress)) >> $env:GITHUB_OUTPUT # Populate further outputs - $deploymentOutput = $res.deploymentOutput | ConvertTo-Json -Depth 99 -Compress + $deploymentOutput = ($res.deploymentOutput | ConvertTo-Json -Depth 99 -Compress) -replace "'", "''" # Escaping single quotes for resilient access in subsequent steps Write-Output ('{0}={1}' -f 'deploymentOutput', $deploymentOutput) >> $env:GITHUB_OUTPUT Write-Verbose "Deployment output: $deploymentOutput" -Verbose diff --git a/.github/workflows/avm.utl.types.avm-common-types.yml b/.github/workflows/avm.utl.types.avm-common-types.yml new file mode 100644 index 0000000000..13d5ff4e28 --- /dev/null +++ b/.github/workflows/avm.utl.types.avm-common-types.yml @@ -0,0 +1,89 @@ +name: "avm.utl.types.avm-common-types" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: false # true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + default: 'northeurope' + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.utl.types.avm-common-types.yml" + - "avm/utl/types/avm-common-types/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/utl/types/avm-common-types" + workflowPath: ".github/workflows/avm.utl.types.avm-common-types.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index 53a9508953..d5bcbc4eaf 100644 --- a/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/avm/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -667,34 +667,26 @@ Describe 'Module tests' -Tag 'Module' { $udtCases = @( @{ parameterName = 'diagnosticSettings' - udtName = 'diagnosticSettingType' link = "$interfaceBase/diagnostic-settings" } @{ parameterName = 'roleAssignments' - udtName = 'roleAssignmentType' - udtExpectedUrl = "$interfaceBase/role-assignments/udt-schema" link = "$interfaceBase/role-assignments" } @{ parameterName = 'lock' - udtName = 'lockType' - udtExpectedUrl = "$interfaceBase/resource-locks/udt-schema" link = "$interfaceBase/resource-locks" } @{ parameterName = 'managedIdentities' - udtName = 'managedIdentitiesType' link = "$interfaceBase/managed-identities" } @{ parameterName = 'privateEndpoints' - udtName = 'privateEndpointType' link = "$interfaceBase/private-endpoints" } @{ parameterName = 'customerManagedKey' - udtName = 'customerManagedKeyType' link = "$interfaceBase/customer-managed-keys" } ) @@ -705,86 +697,29 @@ Describe 'Module tests' -Tag 'Module' { templateFileContent = $templateFileContent templateFileContentBicep = Get-Content $templateFilePath parameterName = $udtCase.parameterName - udtName = $udtCase.udtName expectedUdtUrl = $udtCase.udtExpectedUrl ? $udtCase.udtExpectedUrl : '' link = $udtCase.link } } } - It '[] If template has a parameter [], it should implement the user-defined type []' -TestCases $udtTestCases { + It '[] If template has a parameter [], it should implement AVM''s corresponding user-defined type.' -TestCases $udtTestCases { param( [hashtable] $templateFileContent, [string[]] $templateFileContentBicep, [string] $parameterName, - [string] $udtName, - [string] $expectedUdtUrl, [string] $link ) if ($templateFileContent.parameters.Keys -contains $parameterName) { - $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type. For information please review the [AVM Specs]($link)." - $templateFileContent.parameters.$parameterName.'$ref' | Should -Be "#/definitions/$udtName" -Because "the [$parameterName] parameter should use a user-defined type [$udtName]. For information please review the [AVM Specs]($link)." - - if (-not [String]::IsNullOrEmpty($expectedUdtUrl)) { - $implementedSchemaStartIndex = $templateFileContentBicep.IndexOf("type $udtName = {") - $implementedSchemaEndIndex = $implementedSchemaStartIndex + 1 - while ($templateFileContentBicep[$implementedSchemaEndIndex] -notmatch '^\}.*' -and $implementedSchemaEndIndex -lt $templateFileContentBicep.Length) { - $implementedSchemaEndIndex++ - } - if ($implementedSchemaEndIndex -eq $templateFileContentBicep.Length) { - throw "Failed to identify [$udtName] user-defined type in template." - } - $implementedSchema = $templateFileContentBicep[$implementedSchemaStartIndex..$implementedSchemaEndIndex] - - try { - $rawResponse = Invoke-WebRequest -Uri $expectedUdtUrl - if (($rawResponse.Headers['Content-Type'] | Out-String) -like '*text/plain*') { - $expectedSchemaFull = $rawResponse.Content -split '\n' - } else { - throw "Failed to fetch schema from [$expectedUdtUrl]. Skipping schema check" - } - } catch { - Write-Warning "Failed to fetch schema from [$expectedUdtUrl]. Skipping schema check" - return - } - - $expectedSchemaStartIndex = $expectedSchemaFull.IndexOf("type $udtName = {") - $expectedSchemaEndIndex = $expectedSchemaStartIndex + 1 - while ($expectedSchemaFull[$expectedSchemaEndIndex] -notmatch '^\}.*' -and $expectedSchemaEndIndex -lt $expectedSchemaFull.Length) { - $expectedSchemaEndIndex++ - } - if ($expectedSchemaEndIndex -eq $expectedSchemaFull.Length) { - throw "Failed to identify [$udtName] user-defined type in expected schema at URL [$expectedUdtUrl]." - } - $expectedSchema = $expectedSchemaFull[$expectedSchemaStartIndex..$expectedSchemaEndIndex] - if ($templateFileContentBicep -match '@sys\.([a-zA-Z]+)\(') { - # Handing cases where the template may use the @sys namespace explicitly - $expectedSchema = $expectedSchema | ForEach-Object { $_ -replace '@([a-zA-Z]+)\(', '@sys.$1(' } - } - - $formattedDiff = @() - foreach ($finding in (Compare-Object $implementedSchema $expectedSchema)) { - if ($finding.SideIndicator -eq '=>') { - $formattedDiff += ('+ {0}' -f $finding.InputObject) - } elseif ($finding.SideIndicator -eq '<=') { - $formattedDiff += ('- {0}' -f $finding.InputObject) - } - } - - if ($formattedDiff.Count -gt 0) { - $warningMessage = "The implemented user-defined type is not the same as the expected user-defined type ({0}) defined in the AVM specs ({1}) and should not have diff`n{2}" -f $expectedUdtUrl, $link, ($formattedDiff | Out-String) - Write-Warning $warningMessage - - # Adding also to output to show in GitHub CI - $mdFormattedDiff = ($formattedDiff -join '
    ') -replace '\|', '\|' - $mdFormattedWarningMessage = 'The implemented user-defined type is not the same as the expected [user-defined type]({0}) defined in the [AVM specs]({1}) and should not have diff

    {2}
    ' -f $expectedUdtUrl, $link, $mdFormattedDiff - Write-Output @{ - Warning = $mdFormattedWarningMessage - } - } + if ($templateFileContent.parameters.$parameterName.Keys -contains 'items') { + # If parameter is an array, the UDT may focus on each element + $templateFileContent.parameters.$parameterName.items.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type. For information please review the [AVM Specs]($link)." + } else { + # If not, the parameter itself should reference a UDT + $templateFileContent.parameters.$parameterName.Keys | Should -Contain '$ref' -Because "the [$parameterName] parameter should use a user-defined type. For information please review the [AVM Specs]($link)." } } else { Set-ItResult -Skipped -Because "the module template has no [$parameterName] parameter." diff --git a/avm/utl/types/avm-common-types/README.md b/avm/utl/types/avm-common-types/README.md new file mode 100644 index 0000000000..97107533ab --- /dev/null +++ b/avm/utl/types/avm-common-types/README.md @@ -0,0 +1,331 @@ +# Default interface types for AVM modules `[Types/AvmCommonTypes]` + +This module provides you with all common variants for AVM interfaces to be used in AVM modules. + +Details for how to implement these interfaces can be found in the AVM documentation [here](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces). + + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## 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/utl/types/avm-common-types:`. + +- [Import all](#example-1-import-all) + +### Example 1: _Import all_ + +This example imports all available types of the given module. + +Note: In your module you would import only the types you need. + + + +
    + +via Bicep module + +```bicep +targetScope = 'subscription' + +metadata name = 'Import all' +metadata description = ''' +This example imports all available types of the given module. + +Note: In your module you would import only the types you need. +''' + +// ============== // +// Test Execution // +// ============== // + +import { + customerManagedKeyType + diagnosticSettingFullType + diagnosticSettingLogsOnlyType + diagnosticSettingMetricsOnlyType + roleAssignmentType + lockType + managedIdentityAllType + managedIdentityOnlySysAssignedType + managedIdentityOnlyUserAssignedType + privateEndpointMultiServiceType + privateEndpointSingleServiceType + secretToSetType + secretSetType +} from '../../../main.bicep' // Would be: br/public:avm/utl/types/avm-common-types: + +// ====================== // +// Diagnostic Settings // +// ====================== // +param diagnosticFull diagnosticSettingFullType[] = [ + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + logAnalyticsDestinationType: 'AzureDiagnostics' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + marketplacePartnerResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Datadog/monitors/dd1' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'mySettings' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } +] +output diagnosticFullOutput diagnosticSettingFullType[] = diagnosticFull + +param diagnosticMetricsOnly diagnosticSettingMetricsOnlyType[] = [ + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + logAnalyticsDestinationType: 'AzureDiagnostics' + marketplacePartnerResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Datadog/monitors/dd1' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'mySettings' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } +] +output diagnosticMetricsOnlyOutput diagnosticSettingFullType[] = diagnosticMetricsOnly + +param diagnosticLogsOnly diagnosticSettingLogsOnlyType[] = [ + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + logAnalyticsDestinationType: 'AzureDiagnostics' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + marketplacePartnerResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Datadog/monitors/dd1' + name: 'mySettings' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } +] +output diagnosticLogsOnlyOutput diagnosticSettingFullType[] = diagnosticLogsOnly + +// =================== // +// Role Assignments // +// =================== // +param roleAssignments roleAssignmentType[] = [ + { + principalId: '11111111-1111-1111-1111-111111111111' + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) // Reader + condition: '((!(ActionMatches{\'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read\'})) OR (@Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name] StringEquals \'blobs-example-container\'))' + conditionVersion: '2.0' + delegatedManagedIdentityResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' + description: 'my description' + name: 'myRoleAssignment' + principalType: 'ServicePrincipal' + } + { + principalId: '22222222-2222-2222-2222-222222222222' + roleDefinitionIdOrName: 'Reader' + principalType: 'ServicePrincipal' + } + { + principalId: '33333333-3333-3333-3333-333333333333' + roleDefinitionIdOrName: 'acdd72a7-3385-48ef-bd42-f606fba81ae7' //Reader + principalType: 'ServicePrincipal' + } +] +output roleAssignmentsOutput roleAssignmentType[] = roleAssignments + +// ========= // +// Locks // +// ========= // +param lock lockType = { + kind: 'CanNotDelete' + name: 'myLock' +} +output lockOutput lockType = lock + +// ====================== // +// Managed Idenitites // +// ====================== // +param managedIdentityFull managedIdentityAllType = { + systemAssigned: true + userAssignedResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' + ] +} +output managedIdentityFullOutput managedIdentityAllType = managedIdentityFull + +param managedIdentityOnlySysAssigned managedIdentityOnlySysAssignedType = { + systemAssigned: true +} +output managedIdentityOnlySysAssignedOutput managedIdentityAllType = managedIdentityOnlySysAssigned + +param managedIdentityOnlyUserAssigned managedIdentityOnlyUserAssignedType = { + userAssignedResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' + ] +} +output managedIdentityOnlyUserAssignedOutput managedIdentityAllType = managedIdentityOnlyUserAssigned + +// ===================== // +// Private Endpoints // +// ===================== // +param privateEndpointMultiService privateEndpointMultiServiceType[] = [ + { + lock: { + kind: 'CanNotDelete' + name: 'myLock' + } + roleAssignments: [ + { + principalId: '11111111-1111-1111-1111-111111111111' + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) // Reader + } + ] + subnetResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/defaultSubnet' + service: 'blob' + applicationSecurityGroupResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/applicationSecurityGroups/myAsg' + ] + customDnsConfigs: [ + { + ipAddresses: [ + '1.2.3.4' + ] + } + ] + customNetworkInterfaceName: 'myInterface' + ipConfigurations: [ + { + name: 'myIpConfig' + properties: { + groupId: 'blob' + memberName: 'blob' + privateIPAddress: '1.2.3.4' + } + } + ] + isManualConnection: false + location: 'WestEurope' + manualConnectionRequestMessage: 'Please approve this connection.' + name: 'myPrivateEndpoint' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/privateDnsZones/myZone' + name: 'myConfig' + } + ] + } + privateLinkServiceConnectionName: 'myConnection' + resourceGroupName: 'myResourceGroup' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +output privateEndpointMultiServiceOutput privateEndpointMultiServiceType[] = privateEndpointMultiService + +param privateEndpointSingleService privateEndpointSingleServiceType[] = [ + { + subnetResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/defaultSubnet' + } +] +output privateEndpointSingleServiceOutput privateEndpointSingleServiceType[] = privateEndpointSingleService + +// ======================== // +// Customer-Managed Keys // +// ======================== // +param customerManagedKeyFull customerManagedKeyType = { + keyName: 'myKey' + keyVaultResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.KeyVault/vaults/myVault' + keyVersion: '2f4783701d724537a4e0c2d473c31846' + userAssignedIdentityResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' +} +output customerManagedKeyFullOutput customerManagedKeyType = customerManagedKeyFull + +param customerManagedKeyDefaults customerManagedKeyType = { + keyName: 'myKey' + keyVaultResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.KeyVault/vaults/myVault' +} +output customerManagedKeyDefaultsOutput customerManagedKeyType = customerManagedKeyDefaults + +// ================== // +// Secrets Export // +// ================== // +param secretToSet secretToSetType[] = [ + { + name: 'mySecret' + value: 'definitelyAValue' + } +] +#disable-next-line outputs-should-not-contain-secrets // Does not contain a secret +output secretToSetOutput secretToSetType[] = secretToSet + +param secretSet secretSetType[] = [ + { + secretResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.KeyVault/vaults/myVault/secrets/mySecret' + secretUri: 'https://myVault.${az.environment().suffixes.keyvaultDns}/secrets/mySecret' + secretUriWithVersion: 'https://myVault.${az.environment().suffixes.keyvaultDns}/secrets/mySecret/2f4783701d724537a4e0c2d473c31846' + } +] +output secretSetOutput secretSetType[] = secretSet +``` + +
    +

    + +## Parameters + +_None_ + +## Outputs + +_None_ diff --git a/avm/utl/types/avm-common-types/main.bicep b/avm/utl/types/avm-common-types/main.bicep new file mode 100644 index 0000000000..a39b2a2331 --- /dev/null +++ b/avm/utl/types/avm-common-types/main.bicep @@ -0,0 +1,404 @@ +metadata name = 'Default interface types for AVM modules' +metadata description = ''' +This module provides you with all common variants for AVM interfaces to be used in AVM modules. + +Details for how to implement these interfaces can be found in the AVM documentation [here](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces). +''' + +// ====================== // +// Diagnostic Settings // +// ====================== // + +// Type with all properties available +@export() +type diagnosticSettingFullType = { + @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 with only metrics available +@export() +type diagnosticSettingMetricsOnlyType = { + @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? +} + +// Type with only logs available +@export() +type diagnosticSettingLogsOnlyType = { + @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? +} + +// =================== // +// Role Assignments // +// =================== // + +@export() +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? +} + +// ========= // +// Locks // +// ========= // + +@export() +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +} + +// ====================== // +// Managed Identities // +// ====================== // + +// Type with all properties available +@export() +type managedIdentityAllType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption.') + userAssignedResourceIds: string[]? +} + +// Type with only system-assigned identities available +@export() +type managedIdentityOnlySysAssignedType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? +} + +// Type with only user-assigned identities available +@export() +type managedIdentityOnlyUserAssignedType = { + @description('Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption.') + userAssignedResourceIds: string[]? +} + +// ===================== // +// Private Endpoints // +// ===================== // + +type privateEndpointPrivateDnsZoneGroupType = { + @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 + }[] +} + +type privateEndpointCustomDnsConfigType = { + @description('Required. Fqdn that resolves to private endpoint IP address.') + fqdn: string? + + @description('Required. A list of private IP addresses of the private endpoint.') + ipAddresses: string[] +} + +type privateEndpointIpConfigurationType = { + @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 + } +} + +// Type where 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) +@export() +type privateEndpointSingleServiceType = { + @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('Optional. The subresource to deploy the Private Endpoint for. For example "vault" for a Key Vault Private Endpoint.') + 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: privateEndpointPrivateDnsZoneGroupType? + + @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: privateEndpointCustomDnsConfigType[]? + + @description('Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints.') + ipConfigurations: privateEndpointIpConfigurationType[]? + + @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 where 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, ...) +@export() +type privateEndpointMultiServiceType = { + @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" for a Storage Account\'s Private Endpoints.') + 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: privateEndpointPrivateDnsZoneGroupType? + + @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: privateEndpointCustomDnsConfigType[]? + + @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') + ipConfigurations: privateEndpointIpConfigurationType[]? + + @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? +} + +// ======================== // +// Customer-Managed Keys // +// ======================== // + +@export() +type customerManagedKeyType = { + @description('Required. The resource ID of a key vault to reference a customer managed key for encryption from.') + keyVaultResourceId: string + + @description('Required. The name of the customer managed key to use for encryption.') + keyName: string + + @description('Optional. The version of the customer managed key to reference for encryption. If not provided, using \'latest\'.') + keyVersion: string? + + @description('Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use.') + userAssignedIdentityResourceId: string? +} + +// ================== // +// Secrets Export // +// ================== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string + + @description('The secret URI with version of the exported secret.') + secretUriWithVersion: string +} + +@export() +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} + +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/utl/types/avm-common-types/main.json b/avm/utl/types/avm-common-types/main.json new file mode 100644 index 0000000000..9a022457c5 --- /dev/null +++ b/avm/utl/types/avm-common-types/main.json @@ -0,0 +1,934 @@ +{ + "$schema": "https://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": "14970745628674685946" + }, + "name": "Default interface types for AVM modules", + "description": "This module provides you with all common variants for AVM interfaces to be used in AVM modules.\n\nDetails for how to implement these interfaces can be found in the AVM documentation [here](https://azure.github.io/Azure-Verified-Modules/specs/shared/interfaces).\n" + }, + "definitions": { + "diagnosticSettingFullType": { + "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 + } + }, + "diagnosticSettingMetricsOnlyType": { + "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." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "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": { + "__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": { + "__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": { + "__bicep_export!": true + } + }, + "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": { + "__bicep_export!": true + } + }, + "managedIdentityOnlySysAssignedType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "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": { + "__bicep_export!": true + } + }, + "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." + } + } + } + }, + "privateEndpointCustomDnsConfigType": { + "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." + } + } + } + }, + "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." + } + } + } + }, + "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." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/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/privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/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": { + "__bicep_export!": true + } + }, + "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/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/privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/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": { + "__bicep_export!": 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. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretSetType": { + "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": { + "__bicep_export!": true + } + }, + "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": { + "__bicep_export!": true + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + } + }, + "resources": {} +} \ No newline at end of file diff --git a/avm/utl/types/avm-common-types/tests/e2e/import/main.test.bicep b/avm/utl/types/avm-common-types/tests/e2e/import/main.test.bicep new file mode 100644 index 0000000000..1a087297a0 --- /dev/null +++ b/avm/utl/types/avm-common-types/tests/e2e/import/main.test.bicep @@ -0,0 +1,278 @@ +targetScope = 'subscription' + +metadata name = 'Import all' +metadata description = ''' +This example imports all available types of the given module. + +Note: In your module you would import only the types you need. +''' + +// ============== // +// Test Execution // +// ============== // + +import { + customerManagedKeyType + diagnosticSettingFullType + diagnosticSettingLogsOnlyType + diagnosticSettingMetricsOnlyType + roleAssignmentType + lockType + managedIdentityAllType + managedIdentityOnlySysAssignedType + managedIdentityOnlyUserAssignedType + privateEndpointMultiServiceType + privateEndpointSingleServiceType + secretToSetType + secretSetType +} from '../../../main.bicep' // Would be: br/public:avm/utl/types/avm-common-types: + +// ====================== // +// Diagnostic Settings // +// ====================== // +param diagnosticFull diagnosticSettingFullType[] = [ + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + logAnalyticsDestinationType: 'AzureDiagnostics' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + marketplacePartnerResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Datadog/monitors/dd1' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'mySettings' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } +] +output diagnosticFullOutput diagnosticSettingFullType[] = diagnosticFull + +param diagnosticMetricsOnly diagnosticSettingMetricsOnlyType[] = [ + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + logAnalyticsDestinationType: 'AzureDiagnostics' + marketplacePartnerResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Datadog/monitors/dd1' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'mySettings' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } +] +output diagnosticMetricsOnlyOutput diagnosticSettingFullType[] = diagnosticMetricsOnly + +param diagnosticLogsOnly diagnosticSettingLogsOnlyType[] = [ + { + eventHubAuthorizationRuleResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.EventHub/namespaces/myNamespace/eventhubs/myHub/authorizationRules/myRule' + eventHubName: 'myHub' + logAnalyticsDestinationType: 'AzureDiagnostics' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + marketplacePartnerResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Datadog/monitors/dd1' + name: 'mySettings' + storageAccountResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/myStorageAccount' + workspaceResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myRg/providers/Microsoft.OperationalInsights/workspaces/myLaw' + } +] +output diagnosticLogsOnlyOutput diagnosticSettingFullType[] = diagnosticLogsOnly + +// =================== // +// Role Assignments // +// =================== // +param roleAssignments roleAssignmentType[] = [ + { + principalId: '11111111-1111-1111-1111-111111111111' + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) // Reader + condition: '((!(ActionMatches{\'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read\'})) OR (@Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name] StringEquals \'blobs-example-container\'))' + conditionVersion: '2.0' + delegatedManagedIdentityResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' + description: 'my description' + name: 'myRoleAssignment' + principalType: 'ServicePrincipal' + } + { + principalId: '22222222-2222-2222-2222-222222222222' + roleDefinitionIdOrName: 'Reader' + principalType: 'ServicePrincipal' + } + { + principalId: '33333333-3333-3333-3333-333333333333' + roleDefinitionIdOrName: 'acdd72a7-3385-48ef-bd42-f606fba81ae7' //Reader + principalType: 'ServicePrincipal' + } +] +output roleAssignmentsOutput roleAssignmentType[] = roleAssignments + +// ========= // +// Locks // +// ========= // +param lock lockType = { + kind: 'CanNotDelete' + name: 'myLock' +} +output lockOutput lockType = lock + +// ====================== // +// Managed Idenitites // +// ====================== // +param managedIdentityFull managedIdentityAllType = { + systemAssigned: true + userAssignedResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' + ] +} +output managedIdentityFullOutput managedIdentityAllType = managedIdentityFull + +param managedIdentityOnlySysAssigned managedIdentityOnlySysAssignedType = { + systemAssigned: true +} +output managedIdentityOnlySysAssignedOutput managedIdentityAllType = managedIdentityOnlySysAssigned + +param managedIdentityOnlyUserAssigned managedIdentityOnlyUserAssignedType = { + userAssignedResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' + ] +} +output managedIdentityOnlyUserAssignedOutput managedIdentityAllType = managedIdentityOnlyUserAssigned + +// ===================== // +// Private Endpoints // +// ===================== // +param privateEndpointMultiService privateEndpointMultiServiceType[] = [ + { + lock: { + kind: 'CanNotDelete' + name: 'myLock' + } + roleAssignments: [ + { + principalId: '11111111-1111-1111-1111-111111111111' + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) // Reader + } + ] + subnetResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/defaultSubnet' + service: 'blob' + applicationSecurityGroupResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/applicationSecurityGroups/myAsg' + ] + customDnsConfigs: [ + { + ipAddresses: [ + '1.2.3.4' + ] + } + ] + customNetworkInterfaceName: 'myInterface' + ipConfigurations: [ + { + name: 'myIpConfig' + properties: { + groupId: 'blob' + memberName: 'blob' + privateIPAddress: '1.2.3.4' + } + } + ] + isManualConnection: false + location: 'WestEurope' + manualConnectionRequestMessage: 'Please approve this connection.' + name: 'myPrivateEndpoint' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/privateDnsZones/myZone' + name: 'myConfig' + } + ] + } + privateLinkServiceConnectionName: 'myConnection' + resourceGroupName: 'myResourceGroup' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +output privateEndpointMultiServiceOutput privateEndpointMultiServiceType[] = privateEndpointMultiService + +param privateEndpointSingleService privateEndpointSingleServiceType[] = [ + { + subnetResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/defaultSubnet' + } +] +output privateEndpointSingleServiceOutput privateEndpointSingleServiceType[] = privateEndpointSingleService + +// ======================== // +// Customer-Managed Keys // +// ======================== // +param customerManagedKeyFull customerManagedKeyType = { + keyName: 'myKey' + keyVaultResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.KeyVault/vaults/myVault' + keyVersion: '2f4783701d724537a4e0c2d473c31846' + userAssignedIdentityResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity' +} +output customerManagedKeyFullOutput customerManagedKeyType = customerManagedKeyFull + +param customerManagedKeyDefaults customerManagedKeyType = { + keyName: 'myKey' + keyVaultResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.KeyVault/vaults/myVault' +} +output customerManagedKeyDefaultsOutput customerManagedKeyType = customerManagedKeyDefaults + +// ================== // +// Secrets Export // +// ================== // +param secretToSet secretToSetType[] = [ + { + name: 'mySecret' + value: 'definitelyAValue' + } +] +#disable-next-line outputs-should-not-contain-secrets // Does not contain a secret +output secretToSetOutput secretToSetType[] = secretToSet + +param secretSet secretSetType[] = [ + { + secretResourceId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.KeyVault/vaults/myVault/secrets/mySecret' + secretUri: 'https://myVault.${az.environment().suffixes.keyvaultDns}/secrets/mySecret' + secretUriWithVersion: 'https://myVault.${az.environment().suffixes.keyvaultDns}/secrets/mySecret/2f4783701d724537a4e0c2d473c31846' + } +] +output secretSetOutput secretSetType[] = secretSet diff --git a/avm/utl/types/avm-common-types/version.json b/avm/utl/types/avm-common-types/version.json new file mode 100644 index 0000000000..83083db694 --- /dev/null +++ b/avm/utl/types/avm-common-types/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