From 016e9a9e3970265887c1afeb1dd4718ff8a19c0d Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 15:19:10 +0200 Subject: [PATCH 1/8] Fixed ReadMe script & updated nullable --- avm/res/cognitive-services/account/README.md | 16 +++-- avm/res/cognitive-services/account/main.bicep | 12 +++- avm/res/cognitive-services/account/main.json | 61 ++++++++++++------- .../account/tests/e2e/max/main.test.bicep | 1 - avm/res/key-vault/vault/README.md | 16 +++-- avm/res/key-vault/vault/main.bicep | 12 +++- avm/res/key-vault/vault/main.json | 61 ++++++++++++------- .../e2e/private-endpoint/main.test.bicep | 1 - avm/res/network/private-endpoint/README.md | 14 ++--- avm/res/network/private-endpoint/main.bicep | 30 +++++---- avm/res/network/private-endpoint/main.json | 40 +++++++----- .../sharedScripts/Set-ModuleReadMe.ps1 | 49 +++++++++++++-- 12 files changed, 210 insertions(+), 103 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index c14e60d3e1..f02a3592f5 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -172,7 +172,6 @@ module account 'br/public:avm-res-cognitiveservices-account:1.0.0' = { privateDnsZoneResourceIds: [ '' ] - service: 'account' subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -290,7 +289,6 @@ module account 'br/public:avm-res-cognitiveservices-account:1.0.0' = { "privateDnsZoneResourceIds": [ "" ], - "service": "account", "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1175,9 +1173,10 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`lock`](#parameter-privateendpointslock) | No | string | Optional. Specify the type of lock. | | [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | No | array | Optional. Manual PrivateLink Service Connections. | | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | -| [`service`](#parameter-privateendpointsservice) | Yes | string | Required. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1283,6 +1282,13 @@ Optional. The name of the private endpoint. - Required: No - Type: string +### Parameter: `privateEndpoints.privateDnsZoneGroupName` + +Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.privateDnsZoneResourceIds` Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. @@ -1299,9 +1305,9 @@ Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrN ### Parameter: `privateEndpoints.service` -Required. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". -- Required: Yes +- Required: No - Type: string ### Parameter: `privateEndpoints.subnetResourceId` diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index d015ce1a55..73293a58a0 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -267,8 +267,10 @@ resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSetti module cognitiveService_privateEndpoints '../../network/private-endpoint/main.bicep' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-CognitiveService-PrivateEndpoint-${index}' params: { - groupIds: [ + groupIds: contains(privateEndpoint, 'service') ? [ privateEndpoint.service + ] : [ + 'account' ] name: privateEndpoint.?name ?? 'pe-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.service}-${index}' serviceResourceId: cognitiveService.id @@ -276,6 +278,7 @@ module cognitiveService_privateEndpoints '../../network/private-endpoint/main.bi 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 ?? 'default' privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds ?? [] roleAssignments: privateEndpoint.?roleAssignments ?? [] tags: privateEndpoint.?tags ?? {} @@ -392,12 +395,15 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Required. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') - service: string + @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + 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[]? diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 72df1d85a1..f47243a61d 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.21.1.54444", - "templateHash": "10343365646392943955" + "templateHash": "2202997027837395559" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -206,8 +206,9 @@ }, "service": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." } }, "subnetResourceId": { @@ -216,6 +217,13 @@ "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": { @@ -810,11 +818,7 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { - "value": [ - "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service]" - ] - }, + "groupIds": "[if(contains(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), createObject('value', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service)), createObject('value', createArray('account')))]", "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, @@ -833,6 +837,9 @@ "lock": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, + "privateDnsZoneGroupName": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName'), 'default')]" + }, "privateDnsZoneResourceIds": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds'), createArray())]" }, @@ -866,7 +873,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "18008341392159466529" + "templateHash": "10397201760229716051" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -986,21 +993,21 @@ }, "applicationSecurityGroupResourceIds": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, "customNetworkInterfaceName": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, "ipConfigurations": { "type": "array", - "defaultValue": [], + "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." } @@ -1011,9 +1018,16 @@ "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." } }, + "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", - "defaultValue": [], + "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." } @@ -1039,21 +1053,21 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, "customDnsConfigs": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Manual PrivateLink Service Connections." } @@ -1112,16 +1126,16 @@ "copy": [ { "name": "applicationSecurityGroups", - "count": "[length(parameters('applicationSecurityGroupResourceIds'))]", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "id": "[parameters('applicationSecurityGroupResourceIds')[copyIndex('applicationSecurityGroups')]]" + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" } } ], - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", "privateLinkServiceConnections": [ { "name": "[parameters('name')]", @@ -1183,8 +1197,11 @@ }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneResourceIds')]" + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" }, "privateEndpointName": { "value": "[parameters('name')]" 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 046ad7baeb..15c92ac7c8 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 @@ -129,7 +129,6 @@ module testDeployment '../../../main.bicep' = { privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId ] - service: 'account' subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index bdfff68b2f..c920c173d6 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -517,7 +517,6 @@ module vault 'br/public:avm-res-keyvault-vault:1.0.0' = { privateDnsZoneResourceIds: [ '' ] - service: 'vault' subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -564,7 +563,6 @@ module vault 'br/public:avm-res-keyvault-vault:1.0.0' = { "privateDnsZoneResourceIds": [ "" ], - "service": "vault", "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1272,9 +1270,10 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`lock`](#parameter-privateendpointslock) | No | | Optional. Specify the type of lock. | | [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | No | array | Optional. Manual PrivateLink Service Connections. | | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | | Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | -| [`service`](#parameter-privateendpointsservice) | Yes | string | Required. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1379,6 +1378,13 @@ Optional. The name of the private endpoint. - Required: No - Type: string +### Parameter: `privateEndpoints.privateDnsZoneGroupName` + +Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.privateDnsZoneResourceIds` Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. @@ -1395,9 +1401,9 @@ Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrN ### Parameter: `privateEndpoints.service` -Required. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". -- Required: Yes +- Required: No - Type: string ### Parameter: `privateEndpoints.subnetResourceId` diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index bd6bcf09c1..95228a86ed 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -245,8 +245,10 @@ module keyVault_keys 'key/main.bicep' = [for (key, index) in keys: { module keyVault_privateEndpoints '../../network/private-endpoint/main.bicep' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-KeyVault-PrivateEndpoint-${index}' params: { - groupIds: [ + groupIds: contains(privateEndpoint, 'service') ? [ privateEndpoint.service + ] : [ + 'vault' ] name: privateEndpoint.?name ?? 'pe-${last(split(keyVault.id, '/'))}-${privateEndpoint.service}-${index}' serviceResourceId: keyVault.id @@ -254,6 +256,7 @@ module keyVault_privateEndpoints '../../network/private-endpoint/main.bicep' = [ enableTelemetry: enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName ?? 'default' privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds ?? [] roleAssignments: privateEndpoint.?roleAssignments ?? [] tags: privateEndpoint.?tags ?? {} @@ -370,12 +373,15 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Required. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') - service: string + @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + 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[]? diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 6d18b1881b..8957e16edb 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "906532672506379950" + "templateHash": "17531422081011382057" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -206,8 +206,9 @@ }, "service": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." } }, "subnetResourceId": { @@ -216,6 +217,13 @@ "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": { @@ -1348,11 +1356,7 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { - "value": [ - "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service]" - ] - }, + "groupIds": "[if(contains(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), createObject('value', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service)), createObject('value', createArray('vault')))]", "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, @@ -1371,6 +1375,9 @@ "lock": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, + "privateDnsZoneGroupName": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName'), 'default')]" + }, "privateDnsZoneResourceIds": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds'), createArray())]" }, @@ -1404,7 +1411,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "18008341392159466529" + "templateHash": "10397201760229716051" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -1524,21 +1531,21 @@ }, "applicationSecurityGroupResourceIds": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, "customNetworkInterfaceName": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, "ipConfigurations": { "type": "array", - "defaultValue": [], + "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." } @@ -1549,9 +1556,16 @@ "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." } }, + "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", - "defaultValue": [], + "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." } @@ -1577,21 +1591,21 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, "customDnsConfigs": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Manual PrivateLink Service Connections." } @@ -1650,16 +1664,16 @@ "copy": [ { "name": "applicationSecurityGroups", - "count": "[length(parameters('applicationSecurityGroupResourceIds'))]", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "id": "[parameters('applicationSecurityGroupResourceIds')[copyIndex('applicationSecurityGroups')]]" + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" } } ], - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", "privateLinkServiceConnections": [ { "name": "[parameters('name')]", @@ -1721,8 +1735,11 @@ }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneResourceIds')]" + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" }, "privateEndpointName": { "value": "[parameters('name')]" diff --git a/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep b/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep index 15c2a8dd9e..777dc62e79 100644 --- a/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep +++ b/avm/res/key-vault/vault/tests/e2e/private-endpoint/main.test.bicep @@ -52,7 +52,6 @@ module testDeployment '../../../main.bicep' = { privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSResourceId ] - service: 'vault' subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index 137f471953..7d44b73cec 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -403,6 +403,7 @@ module privateEndpoint 'br/public:avm-res-network-privateendpoint:1.0.0' = { | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`manualPrivateLinkServiceConnections`](#parameter-manualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`privateDnsZoneGroupName`](#parameter-privatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | | [`tags`](#parameter-tags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -412,21 +413,18 @@ module privateEndpoint 'br/public:avm-res-network-privateendpoint:1.0.0' = { Application security groups in which the private endpoint IP configuration is included. - Required: No - Type: array -- Default: `[]` ### Parameter: `customDnsConfigs` Custom DNS configurations. - Required: No - Type: array -- Default: `[]` ### Parameter: `customNetworkInterfaceName` The custom name of the network interface attached to the private endpoint. - Required: No - Type: string -- Default: `''` ### Parameter: `enableTelemetry` @@ -446,7 +444,6 @@ Subtype(s) of the connection to be created. The allowed values depend on the typ 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 -- Default: `[]` ### Parameter: `location` @@ -487,7 +484,6 @@ Optional. Specify the name of lock. Manual PrivateLink Service Connections. - Required: No - Type: array -- Default: `[]` ### Parameter: `name` @@ -495,12 +491,17 @@ Name of the private endpoint resource to create. - Required: Yes - Type: string +### Parameter: `privateDnsZoneGroupName` + +The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. +- Required: No +- Type: string + ### Parameter: `privateDnsZoneResourceIds` The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. - Required: No - Type: array -- Default: `[]` ### Parameter: `roleAssignments` @@ -587,7 +588,6 @@ Resource ID of the subnet where the endpoint needs to be created. Tags to be applied on all resources/resource groups in this deployment. - Required: No - Type: object -- Default: `{object}` ## Outputs diff --git a/avm/res/network/private-endpoint/main.bicep b/avm/res/network/private-endpoint/main.bicep index 0aa005c00e..3a27c01277 100644 --- a/avm/res/network/private-endpoint/main.bicep +++ b/avm/res/network/private-endpoint/main.bicep @@ -12,19 +12,22 @@ param subnetResourceId string param serviceResourceId string @description('Optional. Application security groups in which the private endpoint IP configuration is included.') -param applicationSecurityGroupResourceIds array = [] +param applicationSecurityGroupResourceIds array? @description('Optional. The custom name of the network interface attached to the private endpoint.') -param customNetworkInterfaceName string = '' +param customNetworkInterfaceName string? @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') -param ipConfigurations array = [] +param ipConfigurations array? @description('Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to.') param groupIds array +@description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') +param privateDnsZoneGroupName string? + @description('Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones.') -param privateDnsZoneResourceIds array = [] +param privateDnsZoneResourceIds array? @description('Optional. Location for all Resources.') param location string = resourceGroup().location @@ -36,13 +39,13 @@ param lock lockType param roleAssignments roleAssignmentType @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') -param tags object = {} +param tags object? @description('Optional. Custom DNS configurations.') -param customDnsConfigs array = [] +param customDnsConfigs array? @description('Optional. Manual PrivateLink Service Connections.') -param manualPrivateLinkServiceConnections array = [] +param manualPrivateLinkServiceConnections array? @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true @@ -86,13 +89,13 @@ resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { location: location tags: tags properties: { - applicationSecurityGroups: [for applicationSecurityGroupResourceId in applicationSecurityGroupResourceIds: { + applicationSecurityGroups: [for applicationSecurityGroupResourceId in (applicationSecurityGroupResourceIds ?? []): { id: applicationSecurityGroupResourceId }] - customDnsConfigs: customDnsConfigs - customNetworkInterfaceName: customNetworkInterfaceName - ipConfigurations: ipConfigurations - manualPrivateLinkServiceConnections: manualPrivateLinkServiceConnections + customDnsConfigs: customDnsConfigs ?? [] + customNetworkInterfaceName: customNetworkInterfaceName ?? '' + ipConfigurations: ipConfigurations ?? [] + manualPrivateLinkServiceConnections: manualPrivateLinkServiceConnections ?? [] privateLinkServiceConnections: [ { name: name @@ -112,7 +115,8 @@ resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { module privateEndpoint_privateDnsZoneGroup 'private-dns-zone-group/main.bicep' = if (!empty(privateDnsZoneResourceIds)) { name: '${uniqueString(deployment().name)}-PrivateEndpoint-PrivateDnsZoneGroup' params: { - privateDNSResourceIds: privateDnsZoneResourceIds + name: privateDnsZoneGroupName ?? 'default' + privateDNSResourceIds: privateDnsZoneResourceIds ?? [] privateEndpointName: privateEndpoint.name } } diff --git a/avm/res/network/private-endpoint/main.json b/avm/res/network/private-endpoint/main.json index f500e40efe..f44265fba5 100644 --- a/avm/res/network/private-endpoint/main.json +++ b/avm/res/network/private-endpoint/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "18008341392159466529" + "templateHash": "10397201760229716051" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -126,21 +126,21 @@ }, "applicationSecurityGroupResourceIds": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, "customNetworkInterfaceName": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, "ipConfigurations": { "type": "array", - "defaultValue": [], + "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." } @@ -151,9 +151,16 @@ "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." } }, + "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", - "defaultValue": [], + "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." } @@ -179,21 +186,21 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, "customDnsConfigs": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Manual PrivateLink Service Connections." } @@ -252,16 +259,16 @@ "copy": [ { "name": "applicationSecurityGroups", - "count": "[length(parameters('applicationSecurityGroupResourceIds'))]", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "id": "[parameters('applicationSecurityGroupResourceIds')[copyIndex('applicationSecurityGroups')]]" + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" } } ], - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", "privateLinkServiceConnections": [ { "name": "[parameters('name')]", @@ -323,8 +330,11 @@ }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneResourceIds')]" + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" }, "privateEndpointName": { "value": "[parameters('name')]" diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 4d3d531b91..8c18d66786 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -198,11 +198,48 @@ function Set-ParametersSection { } else { $type = $parameter.type - $defaultValue = ($parameter.defaultValue -is [array]) ? ('[{0}]' -f (($parameter.defaultValue | Sort-Object) -join ', ')) : (($parameter.defaultValue -is [hashtable]) ? '{object}' : (($parameter.defaultValue -is [string]) -and ($parameter.defaultValue -notmatch '\[\w+\(.*\).*\]') ? '''' + $parameter.defaultValue + '''' : $parameter.defaultValue)) - $required = (-not $defaultValue) + + if ($parameter.defaultValue -is [array]) { + $defaultValue = '[{0}]' -f (($parameter.defaultValue | Sort-Object) -join ', ') + } + elseif ($parameter.defaultValue -is [hashtable]) { + $defaultValue = '{object}' + } + elseif ($parameter.defaultValue -is [string] -and ($parameter.defaultValue -notmatch '\[\w+\(.*\).*\]')) { + $defaultValue = '''' + $parameter.defaultValue + '''' + } + else { + $defaultValue = $parameter.defaultValue + } + + # switch ($parameter.defaultValue) { + # { $PSItem -is [array] } { } + # { $PSItem -is [hashtable] } { } + # { $PSItem -is [string] -and ($PSItem -notmatch '\[\w+\(.*\).*\]') } { } + # Default { $defaultValue = $parameter.defaultValue } + # } + + # $defaultValue = $isArray + # ? ('[{0}]' -f (($parameter.defaultValue | Sort-Object) -join ', ')) + # : ($isObject + # ? '{object}' + # : ($isString -and ($parameter.defaultValue -notmatch '\[\w+\(.*\).*\]') + # ? '''' + $parameter.defaultValue + '''' + # : $parameter.defaultValue)) + $required = -not $defaultValue -and -not $parameter.nullable $rawAllowedValues = $parameter.allowedValues } + + # $RequiredParametersList = $TemplateFileContent.parameters.Keys | Where-Object { + # $hasNoDefaultValue = $TemplateFileContent.parameters[$_].Keys -notcontains 'defaultValue' + # $isUserDefinedType = $TemplateFileContent.parameters[$_].Keys -contains '$ref' + # $isNullable = $TemplateFileContent.parameters[$_]['nullable'] + # $isNullableInRef = $TemplateFileContent.parameters[$_].Keys -contains '$ref' ? $TemplateFileContent.definitions[(Split-Path $TemplateFileContent.parameters[$_].'$ref' -Leaf)]['nullable'] : $false + # (($hasNoDefaultValue -and -not $isUserDefinedType -and -not $isNullable) -or ($isUserDefinedType -and -not $isNullableInRef)) + # } | Sort-Object + + # Prepare the links to local headers $paramHeader = '### Parameter: `{0}`' -f $parameter.name $paramIdentifier = ('#{0}' -f $paramHeader.TrimStart('#').Trim().ToLower()) -replace '[:|`]' -replace ' ', '-' @@ -1065,12 +1102,12 @@ function Set-UsageExamplesSection { $testFilePaths = Get-ModuleTestFileList -ModulePath $moduleRoot | ForEach-Object { Join-Path $moduleRoot $_ } - $RequiredParametersList = $TemplateFileContent.parameters.Keys - | Where-Object { + $RequiredParametersList = $TemplateFileContent.parameters.Keys | Where-Object { $hasNoDefaultValue = $TemplateFileContent.parameters[$_].Keys -notcontains 'defaultValue' $isUserDefinedType = $TemplateFileContent.parameters[$_].Keys -contains '$ref' - $isNullable = $TemplateFileContent.parameters[$_].Keys -contains '$ref' ? $TemplateFileContent.definitions[(Split-Path $TemplateFileContent.parameters[$_].'$ref' -Leaf)]['nullable'] : $false - (($hasNoDefaultValue -and -not $isUserDefinedType) -or ($isUserDefinedType -and -not $isNullable)) + $isNullable = $TemplateFileContent.parameters[$_]['nullable'] + $isNullableInRef = $TemplateFileContent.parameters[$_].Keys -contains '$ref' ? $TemplateFileContent.definitions[(Split-Path $TemplateFileContent.parameters[$_].'$ref' -Leaf)]['nullable'] : $false + (($hasNoDefaultValue -and -not $isUserDefinedType -and -not $isNullable) -or ($isUserDefinedType -and -not $isNullableInRef)) } | Sort-Object ############################ From c3f9cdb9490ba9be240b196f39cecb3ef439f890 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 15:54:52 +0200 Subject: [PATCH 2/8] Further param updates --- avm/res/cognitive-services/account/README.md | 9 +- avm/res/cognitive-services/account/main.bicep | 23 ++-- avm/res/cognitive-services/account/main.json | 25 ++--- avm/res/key-vault/vault/README.md | 4 - .../key-vault/vault/access-policy/README.md | 1 - .../key-vault/vault/access-policy/main.bicep | 4 +- .../key-vault/vault/access-policy/main.json | 32 ++++-- avm/res/key-vault/vault/key/README.md | 6 - avm/res/key-vault/vault/key/main.bicep | 20 ++-- avm/res/key-vault/vault/key/main.json | 22 ++-- avm/res/key-vault/vault/main.bicep | 14 +-- avm/res/key-vault/vault/main.json | 104 ++++++++++-------- avm/res/key-vault/vault/secret/README.md | 1 - avm/res/key-vault/vault/secret/main.bicep | 2 +- avm/res/key-vault/vault/secret/main.json | 4 +- 15 files changed, 135 insertions(+), 136 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index f02a3592f5..2ba8b35700 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -874,14 +874,12 @@ module account 'br/public:avm-res-cognitiveservices-account:1.0.0' = { List of allowed FQDN. - Required: No - Type: array -- Default: `[]` ### Parameter: `apiProperties` The API properties for special APIs. - Required: No - Type: object -- Default: `{object}` ### Parameter: `customerManagedKey` @@ -930,7 +928,6 @@ Optional. User assigned identity to use when fetching the customer managed key. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set. - Required: No - Type: string -- Default: `''` ### Parameter: `diagnosticSettings` @@ -1140,7 +1137,6 @@ Optional. The resource ID(s) to assign to the resource. Required if a user assig Resource migration token. - Required: No - Type: string -- Default: `''` ### Parameter: `name` @@ -1329,8 +1325,7 @@ Optional. Tags to be applied on all resources/resource groups in this deployment Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. - Required: No - Type: string -- Default: `''` -- Allowed: `['', Disabled, Enabled]` +- Allowed: `[Disabled, Enabled]` ### Parameter: `restore` @@ -1427,14 +1422,12 @@ SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' Tags of the resource. - Required: No - Type: object -- Default: `{object}` ### Parameter: `userOwnedStorage` The storage accounts for this resource. - Required: No - Type: array -- Default: `[]` ## Outputs diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 73293a58a0..2518d58f2e 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -62,14 +62,13 @@ param diagnosticSettings diagnosticSettingType @description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') @allowed([ - '' 'Enabled' 'Disabled' ]) -param publicNetworkAccess string = '' +param publicNetworkAccess string? @description('Conditional. Subdomain name used for token-based authentication. Required if \'networkAcls\' or \'privateEndpoints\' are set.') -param customSubDomainName string = '' +param customSubDomainName string? @description('Optional. A collection of rules governing the accessibility from specific network locations.') param networkAcls object = {} @@ -84,13 +83,13 @@ param lock lockType param roleAssignments roleAssignmentType @description('Optional. Tags of the resource.') -param tags object = {} +param tags object? @description('Optional. List of allowed FQDN.') -param allowedFqdnList array = [] +param allowedFqdnList array? @description('Optional. The API properties for special APIs.') -param apiProperties object = {} +param apiProperties object? @description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') param disableLocalAuth bool = true @@ -102,7 +101,7 @@ param customerManagedKey customerManagedKeyType param dynamicThrottlingEnabled bool = false @description('Optional. Resource migration token.') -param migrationToken string = '' +param migrationToken string? @description('Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists.') param restore bool = false @@ -111,7 +110,7 @@ param restore bool = false param restrictOutboundNetworkAccess bool = true @description('Optional. The storage accounts for this resource.') -param userOwnedStorage array = [] +param userOwnedStorage array? @description('Optional. The managed identity definition for this resource.') param managedIdentities managedIdentitiesType @@ -202,13 +201,13 @@ resource cognitiveService 'Microsoft.CognitiveServices/accounts@2022-12-01' = { name: sku } properties: { - customSubDomainName: !empty(customSubDomainName) ? customSubDomainName : null + customSubDomainName: customSubDomainName networkAcls: !empty(networkAcls) ? { defaultAction: contains(networkAcls, 'defaultAction') ? networkAcls.defaultAction : null virtualNetworkRules: contains(networkAcls, 'virtualNetworkRules') ? networkAcls.virtualNetworkRules : [] ipRules: contains(networkAcls, 'ipRules') ? networkAcls.ipRules : [] } : null - publicNetworkAccess: !empty(publicNetworkAccess) ? any(publicNetworkAccess) : (!empty(privateEndpoints) && empty(networkAcls) ? 'Disabled' : null) + publicNetworkAccess: publicNetworkAccess ?? (!empty(privateEndpoints) && empty(networkAcls) ? 'Disabled' : null) allowedFqdnList: allowedFqdnList apiProperties: apiProperties disableLocalAuth: disableLocalAuth @@ -221,10 +220,10 @@ resource cognitiveService 'Microsoft.CognitiveServices/accounts@2022-12-01' = { keyVersion: !empty(customerManagedKey.?keyVersion ?? '') ? customerManagedKey!.keyVersion : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) } } : null - migrationToken: !empty(migrationToken) ? migrationToken : null + migrationToken: migrationToken restore: restore restrictOutboundNetworkAccess: restrictOutboundNetworkAccess - userOwnedStorage: !empty(userOwnedStorage) ? userOwnedStorage : null + userOwnedStorage: userOwnedStorage dynamicThrottlingEnabled: dynamicThrottlingEnabled } } diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index f47243a61d..ebd16d78e1 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.21.1.54444", - "templateHash": "2202997027837395559" + "templateHash": "8018230936247253236" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -503,9 +503,8 @@ }, "publicNetworkAccess": { "type": "string", - "defaultValue": "", + "nullable": true, "allowedValues": [ - "", "Enabled", "Disabled" ], @@ -515,7 +514,7 @@ }, "customSubDomainName": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." } @@ -547,21 +546,21 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Tags of the resource." } }, "allowedFqdnList": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. List of allowed FQDN." } }, "apiProperties": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. The API properties for special APIs." } @@ -588,7 +587,7 @@ }, "migrationToken": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Resource migration token." } @@ -609,7 +608,7 @@ }, "userOwnedStorage": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. The storage accounts for this resource." } @@ -727,17 +726,17 @@ "name": "[parameters('sku')]" }, "properties": { - "customSubDomainName": "[if(not(empty(parameters('customSubDomainName'))), parameters('customSubDomainName'), null())]", + "customSubDomainName": "[parameters('customSubDomainName')]", "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('defaultAction', if(contains(parameters('networkAcls'), 'defaultAction'), parameters('networkAcls').defaultAction, null()), 'virtualNetworkRules', if(contains(parameters('networkAcls'), 'virtualNetworkRules'), parameters('networkAcls').virtualNetworkRules, createArray()), 'ipRules', if(contains(parameters('networkAcls'), 'ipRules'), parameters('networkAcls').ipRules, createArray())), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "publicNetworkAccess": "[coalesce(parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", "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": "[if(not(empty(parameters('migrationToken'))), parameters('migrationToken'), null())]", + "migrationToken": "[parameters('migrationToken')]", "restore": "[parameters('restore')]", "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", - "userOwnedStorage": "[if(not(empty(parameters('userOwnedStorage'))), parameters('userOwnedStorage'), null())]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" }, "dependsOn": [ diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index c920c173d6..8395845f86 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -1025,7 +1025,6 @@ module vault 'br/public:avm-res-keyvault-vault:1.0.0' = { All access policies to create. - Required: No - Type: array -- Default: `[]` ### Parameter: `createMode` @@ -1203,7 +1202,6 @@ Specifies if the vault is enabled for a template deployment. All keys to create. - Required: No - Type: array -- Default: `[]` ### Parameter: `location` @@ -1501,7 +1499,6 @@ Required. The name of the role to assign. If it cannot be found you can specify All secrets to create. - Required: No - Type: secureObject -- Default: `{object}` ### Parameter: `sku` @@ -1523,7 +1520,6 @@ softDelete data retention days. It accepts >=7 and <=90. Resource tags. - Required: No - Type: object -- Default: `{object}` ## Outputs diff --git a/avm/res/key-vault/vault/access-policy/README.md b/avm/res/key-vault/vault/access-policy/README.md index 1ce4861bee..f3fbb5be3b 100644 --- a/avm/res/key-vault/vault/access-policy/README.md +++ b/avm/res/key-vault/vault/access-policy/README.md @@ -34,7 +34,6 @@ This module deploys a Key Vault Access Policy. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID. - Required: No - Type: array -- Default: `[]` ### Parameter: `keyVaultName` diff --git a/avm/res/key-vault/vault/access-policy/main.bicep b/avm/res/key-vault/vault/access-policy/main.bicep index e94a15be30..d037981e0c 100644 --- a/avm/res/key-vault/vault/access-policy/main.bicep +++ b/avm/res/key-vault/vault/access-policy/main.bicep @@ -6,9 +6,9 @@ metadata owner = 'Azure/module-maintainers' param keyVaultName string @description('Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault\'s tenant ID.') -param accessPolicies array = [] +param accessPolicies array? -var formattedAccessPolicies = [for accessPolicy in accessPolicies: { +var formattedAccessPolicies = [for accessPolicy in (accessPolicies ?? []): { applicationId: contains(accessPolicy, 'applicationId') ? accessPolicy.applicationId : '' objectId: contains(accessPolicy, 'objectId') ? accessPolicy.objectId : '' permissions: accessPolicy.permissions diff --git a/avm/res/key-vault/vault/access-policy/main.json b/avm/res/key-vault/vault/access-policy/main.json index 4d1bf97394..4ecbcbe1f7 100644 --- a/avm/res/key-vault/vault/access-policy/main.json +++ b/avm/res/key-vault/vault/access-policy/main.json @@ -1,11 +1,12 @@ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "5988194349836968099" + "templateHash": "10553793947812900894" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -20,7 +21,7 @@ }, "accessPolicies": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." } @@ -30,26 +31,35 @@ "copy": [ { "name": "formattedAccessPolicies", - "count": "[length(parameters('accessPolicies'))]", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", "input": { - "applicationId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'applicationId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].applicationId, '')]", - "objectId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'objectId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].objectId, '')]", - "permissions": "[parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'tenantId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].tenantId, tenant().tenantId)]" + "applicationId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].applicationId, '')]", + "objectId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'objectId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId, '')]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].tenantId, tenant().tenantId)]" } } ] }, - "resources": [ - { + "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", diff --git a/avm/res/key-vault/vault/key/README.md b/avm/res/key-vault/vault/key/README.md index d636083a54..c72180c842 100644 --- a/avm/res/key-vault/vault/key/README.md +++ b/avm/res/key-vault/vault/key/README.md @@ -57,14 +57,12 @@ Determines whether the object is enabled. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible. - Required: No - Type: int -- Default: `-1` ### Parameter: `attributesNbf` Not before date in seconds since 1970-01-01T00:00:00Z. - Required: No - Type: int -- Default: `-1` ### Parameter: `curveName` @@ -79,7 +77,6 @@ The elliptic curve name. Array of JsonWebKeyOperation. - Required: No - Type: array -- Default: `[]` - Allowed: `[decrypt, encrypt, import, sign, unwrapKey, verify, wrapKey]` ### Parameter: `keySize` @@ -87,7 +84,6 @@ Array of JsonWebKeyOperation. The key size in bits. For example: 2048, 3072, or 4096 for RSA. - Required: No - Type: int -- Default: `-1` ### Parameter: `keyVaultName` @@ -182,14 +178,12 @@ Required. The name of the role to assign. If it cannot be found you can specify Key rotation policy properties object. - Required: No - Type: object -- Default: `{object}` ### Parameter: `tags` Resource tags. - Required: No - Type: object -- Default: `{object}` ## Outputs diff --git a/avm/res/key-vault/vault/key/main.bicep b/avm/res/key-vault/vault/key/main.bicep index 6d1ee8d9f2..5df7e1309b 100644 --- a/avm/res/key-vault/vault/key/main.bicep +++ b/avm/res/key-vault/vault/key/main.bicep @@ -9,16 +9,16 @@ param keyVaultName string param name string @description('Optional. Resource tags.') -param tags object = {} +param tags object? @description('Optional. Determines whether the object is enabled.') param attributesEnabled bool = true @description('Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible.') -param attributesExp int = -1 +param attributesExp int? @description('Optional. Not before date in seconds since 1970-01-01T00:00:00Z.') -param attributesNbf int = -1 +param attributesNbf int? @description('Optional. The elliptic curve name.') @allowed([ @@ -39,10 +39,10 @@ param curveName string = 'P-256' 'verify' 'wrapKey' ]) -param keyOps array = [] +param keyOps array? @description('Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA.') -param keySize int = -1 +param keySize int? @description('Optional. The type of the key.') @allowed([ @@ -57,7 +57,7 @@ param kty string = 'EC' param roleAssignments roleAssignmentType @description('Optional. Key rotation policy properties object.') -param rotationPolicy object = {} +param rotationPolicy object? var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') @@ -87,14 +87,14 @@ resource key 'Microsoft.KeyVault/vaults/keys@2022-07-01' = { properties: { attributes: { enabled: attributesEnabled - exp: attributesExp != -1 ? attributesExp : null - nbf: attributesNbf != -1 ? attributesNbf : null + exp: attributesExp + nbf: attributesNbf } curveName: curveName keyOps: keyOps - keySize: keySize != -1 ? keySize : null + keySize: keySize kty: kty - rotationPolicy: !empty(rotationPolicy) ? rotationPolicy : null + rotationPolicy: rotationPolicy } } diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index f7b1d198aa..8588273eb3 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "6796710145791572557" + "templateHash": "2337714221072963213" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -95,7 +95,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } @@ -109,14 +109,14 @@ }, "attributesExp": { "type": "int", - "defaultValue": -1, + "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", - "defaultValue": -1, + "nullable": true, "metadata": { "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." } @@ -136,7 +136,7 @@ }, "keyOps": { "type": "array", - "defaultValue": [], + "nullable": true, "allowedValues": [ "decrypt", "encrypt", @@ -152,7 +152,7 @@ }, "keySize": { "type": "int", - "defaultValue": -1, + "nullable": true, "metadata": { "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." } @@ -178,7 +178,7 @@ }, "rotationPolicy": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Key rotation policy properties object." } @@ -217,14 +217,14 @@ "properties": { "attributes": { "enabled": "[parameters('attributesEnabled')]", - "exp": "[if(not(equals(parameters('attributesExp'), -1)), parameters('attributesExp'), null())]", - "nbf": "[if(not(equals(parameters('attributesNbf'), -1)), parameters('attributesNbf'), null())]" + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" }, "curveName": "[parameters('curveName')]", "keyOps": "[parameters('keyOps')]", - "keySize": "[if(not(equals(parameters('keySize'), -1)), parameters('keySize'), null())]", + "keySize": "[parameters('keySize')]", "kty": "[parameters('kty')]", - "rotationPolicy": "[if(not(empty(parameters('rotationPolicy'))), parameters('rotationPolicy'), null())]" + "rotationPolicy": "[parameters('rotationPolicy')]" }, "dependsOn": [ "keyVault" diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index 95228a86ed..cb5dd2d011 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -13,14 +13,14 @@ param name string param location string = resourceGroup().location @description('Optional. All access policies to create.') -param accessPolicies array = [] +param accessPolicies array? @description('Optional. All secrets to create.') @secure() -param secrets object = {} +param secrets object? @description('Optional. All keys to create.') -param keys array = [] +param keys array? @description('Optional. Specifies if the vault is enabled for deployment by script or compute.') param enableVaultForDeployment bool = true @@ -74,7 +74,7 @@ param roleAssignments roleAssignmentType param privateEndpoints privateEndpointType @description('Optional. Resource tags.') -param tags object = {} +param tags object? @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType @@ -103,14 +103,14 @@ var builtInRoleNames = { 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') } -var formattedAccessPolicies = [for accessPolicy in accessPolicies: { +var formattedAccessPolicies = [for accessPolicy in (accessPolicies ?? []): { applicationId: contains(accessPolicy, 'applicationId') ? accessPolicy.applicationId : '' objectId: contains(accessPolicy, 'objectId') ? accessPolicy.objectId : '' permissions: accessPolicy.permissions tenantId: contains(accessPolicy, 'tenantId') ? accessPolicy.tenantId : tenant().tenantId }] -var secretList = !empty(secrets) ? secrets.secureList : [] +var secretList = secrets.?secureList ?? [] // ============ // // Dependencies // @@ -224,7 +224,7 @@ module keyVault_secrets 'secret/main.bicep' = [for (secret, index) in secretList } }] -module keyVault_keys 'key/main.bicep' = [for (key, index) in keys: { +module keyVault_keys 'key/main.bicep' = [for (key, index) in (keys ?? []): { name: '${uniqueString(deployment().name, location)}-KeyVault-Key-${index}' params: { name: key.name diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 8957e16edb..c02b55da2d 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "17531422081011382057" + "templateHash": "9181741770760472596" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -379,21 +379,21 @@ }, "accessPolicies": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. All access policies to create." } }, "secrets": { "type": "secureObject", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. All secrets to create." } }, "keys": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. All keys to create." } @@ -504,7 +504,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } @@ -527,12 +527,12 @@ "copy": [ { "name": "formattedAccessPolicies", - "count": "[length(parameters('accessPolicies'))]", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", "input": { - "applicationId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'applicationId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].applicationId, '')]", - "objectId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'objectId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].objectId, '')]", - "permissions": "[parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'tenantId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].tenantId, tenant().tenantId)]" + "applicationId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].applicationId, '')]", + "objectId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'objectId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId, '')]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].tenantId, tenant().tenantId)]" } } ], @@ -552,7 +552,7 @@ "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')]" }, - "secretList": "[if(not(empty(parameters('secrets'))), parameters('secrets').secureList, createArray())]", + "secretList": "[coalesce(tryGet(parameters('secrets'), 'secureList'), createArray())]", "moduleVersion": "#_moduleVersion_#" }, "resources": { @@ -680,12 +680,13 @@ }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "5988194349836968099" + "templateHash": "10553793947812900894" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -700,7 +701,7 @@ }, "accessPolicies": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." } @@ -710,26 +711,35 @@ "copy": [ { "name": "formattedAccessPolicies", - "count": "[length(parameters('accessPolicies'))]", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", "input": { - "applicationId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'applicationId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].applicationId, '')]", - "objectId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'objectId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].objectId, '')]", - "permissions": "[parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[if(contains(parameters('accessPolicies')[copyIndex('formattedAccessPolicies')], 'tenantId'), parameters('accessPolicies')[copyIndex('formattedAccessPolicies')].tenantId, tenant().tenantId)]" + "applicationId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].applicationId, '')]", + "objectId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'objectId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId, '')]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[if(contains(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].tenantId, tenant().tenantId)]" } } ] }, - "resources": [ - { + "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", @@ -797,7 +807,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "11436599112934051193" + "templateHash": "11602873550277002353" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -886,7 +896,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } @@ -1030,7 +1040,7 @@ "keyVault_keys": { "copy": { "name": "keyVault_keys", - "count": "[length(parameters('keys'))]" + "count": "[length(coalesce(parameters('keys'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -1042,21 +1052,21 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('keys')[copyIndex()].name]" + "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" }, "keyVaultName": { "value": "[parameters('name')]" }, - "attributesEnabled": "[if(contains(parameters('keys')[copyIndex()], 'attributesEnabled'), createObject('value', parameters('keys')[copyIndex()].attributesEnabled), createObject('value', true()))]", - "attributesExp": "[if(contains(parameters('keys')[copyIndex()], 'attributesExp'), createObject('value', parameters('keys')[copyIndex()].attributesExp), createObject('value', -1))]", - "attributesNbf": "[if(contains(parameters('keys')[copyIndex()], 'attributesNbf'), createObject('value', parameters('keys')[copyIndex()].attributesNbf), createObject('value', -1))]", - "curveName": "[if(contains(parameters('keys')[copyIndex()], 'curveName'), createObject('value', parameters('keys')[copyIndex()].curveName), createObject('value', 'P-256'))]", - "keyOps": "[if(contains(parameters('keys')[copyIndex()], 'keyOps'), createObject('value', parameters('keys')[copyIndex()].keyOps), createObject('value', createArray()))]", - "keySize": "[if(contains(parameters('keys')[copyIndex()], 'keySize'), createObject('value', parameters('keys')[copyIndex()].keySize), createObject('value', -1))]", - "kty": "[if(contains(parameters('keys')[copyIndex()], 'kty'), createObject('value', parameters('keys')[copyIndex()].kty), createObject('value', 'EC'))]", - "tags": "[if(contains(parameters('keys')[copyIndex()], 'tags'), createObject('value', parameters('keys')[copyIndex()].tags), createObject('value', createObject()))]", - "roleAssignments": "[if(contains(parameters('keys')[copyIndex()], 'roleAssignments'), createObject('value', parameters('keys')[copyIndex()].roleAssignments), createObject('value', createArray()))]", - "rotationPolicy": "[if(contains(parameters('keys')[copyIndex()], 'rotationPolicy'), createObject('value', parameters('keys')[copyIndex()].rotationPolicy), createObject('value', createObject()))]" + "attributesEnabled": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].attributesEnabled), createObject('value', true()))]", + "attributesExp": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].attributesExp), createObject('value', -1))]", + "attributesNbf": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesNbf'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].attributesNbf), createObject('value', -1))]", + "curveName": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].curveName), createObject('value', 'P-256'))]", + "keyOps": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].keyOps), createObject('value', createArray()))]", + "keySize": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].keySize), createObject('value', -1))]", + "kty": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].kty), createObject('value', 'EC'))]", + "tags": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].tags), createObject('value', createObject()))]", + "roleAssignments": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].roleAssignments), createObject('value', createArray()))]", + "rotationPolicy": "[if(contains(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy'), createObject('value', coalesce(parameters('keys'), createArray())[copyIndex()].rotationPolicy), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1066,7 +1076,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "6796710145791572557" + "templateHash": "2337714221072963213" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -1155,7 +1165,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } @@ -1169,14 +1179,14 @@ }, "attributesExp": { "type": "int", - "defaultValue": -1, + "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", - "defaultValue": -1, + "nullable": true, "metadata": { "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." } @@ -1196,7 +1206,7 @@ }, "keyOps": { "type": "array", - "defaultValue": [], + "nullable": true, "allowedValues": [ "decrypt", "encrypt", @@ -1212,7 +1222,7 @@ }, "keySize": { "type": "int", - "defaultValue": -1, + "nullable": true, "metadata": { "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." } @@ -1238,7 +1248,7 @@ }, "rotationPolicy": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Key rotation policy properties object." } @@ -1277,14 +1287,14 @@ "properties": { "attributes": { "enabled": "[parameters('attributesEnabled')]", - "exp": "[if(not(equals(parameters('attributesExp'), -1)), parameters('attributesExp'), null())]", - "nbf": "[if(not(equals(parameters('attributesNbf'), -1)), parameters('attributesNbf'), null())]" + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" }, "curveName": "[parameters('curveName')]", "keyOps": "[parameters('keyOps')]", - "keySize": "[if(not(equals(parameters('keySize'), -1)), parameters('keySize'), null())]", + "keySize": "[parameters('keySize')]", "kty": "[parameters('kty')]", - "rotationPolicy": "[if(not(empty(parameters('rotationPolicy'))), parameters('rotationPolicy'), null())]" + "rotationPolicy": "[parameters('rotationPolicy')]" }, "dependsOn": [ "keyVault" diff --git a/avm/res/key-vault/vault/secret/README.md b/avm/res/key-vault/vault/secret/README.md index f03a26ca9b..a41948f0cc 100644 --- a/avm/res/key-vault/vault/secret/README.md +++ b/avm/res/key-vault/vault/secret/README.md @@ -93,7 +93,6 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' Resource tags. - Required: No - Type: object -- Default: `{object}` ### Parameter: `value` diff --git a/avm/res/key-vault/vault/secret/main.bicep b/avm/res/key-vault/vault/secret/main.bicep index f5e3cc6e44..b27b24f097 100644 --- a/avm/res/key-vault/vault/secret/main.bicep +++ b/avm/res/key-vault/vault/secret/main.bicep @@ -9,7 +9,7 @@ param keyVaultName string param name string @description('Optional. Resource tags.') -param tags object = {} +param tags object? @description('Optional. Determines whether the object is enabled.') param attributesEnabled bool = true diff --git a/avm/res/key-vault/vault/secret/main.json b/avm/res/key-vault/vault/secret/main.json index 95f678518b..a504eb3f4b 100644 --- a/avm/res/key-vault/vault/secret/main.json +++ b/avm/res/key-vault/vault/secret/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "11436599112934051193" + "templateHash": "11602873550277002353" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -95,7 +95,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } From a62920f43cdc7647ddda567ec03e859059b10bae Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 15:57:55 +0200 Subject: [PATCH 3/8] Cleanup --- .../sharedScripts/Set-ModuleReadMe.ps1 | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 8c18d66786..4360adbe94 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -212,34 +212,10 @@ function Set-ParametersSection { $defaultValue = $parameter.defaultValue } - # switch ($parameter.defaultValue) { - # { $PSItem -is [array] } { } - # { $PSItem -is [hashtable] } { } - # { $PSItem -is [string] -and ($PSItem -notmatch '\[\w+\(.*\).*\]') } { } - # Default { $defaultValue = $parameter.defaultValue } - # } - - # $defaultValue = $isArray - # ? ('[{0}]' -f (($parameter.defaultValue | Sort-Object) -join ', ')) - # : ($isObject - # ? '{object}' - # : ($isString -and ($parameter.defaultValue -notmatch '\[\w+\(.*\).*\]') - # ? '''' + $parameter.defaultValue + '''' - # : $parameter.defaultValue)) $required = -not $defaultValue -and -not $parameter.nullable $rawAllowedValues = $parameter.allowedValues } - - # $RequiredParametersList = $TemplateFileContent.parameters.Keys | Where-Object { - # $hasNoDefaultValue = $TemplateFileContent.parameters[$_].Keys -notcontains 'defaultValue' - # $isUserDefinedType = $TemplateFileContent.parameters[$_].Keys -contains '$ref' - # $isNullable = $TemplateFileContent.parameters[$_]['nullable'] - # $isNullableInRef = $TemplateFileContent.parameters[$_].Keys -contains '$ref' ? $TemplateFileContent.definitions[(Split-Path $TemplateFileContent.parameters[$_].'$ref' -Leaf)]['nullable'] : $false - # (($hasNoDefaultValue -and -not $isUserDefinedType -and -not $isNullable) -or ($isUserDefinedType -and -not $isNullableInRef)) - # } | Sort-Object - - # Prepare the links to local headers $paramHeader = '### Parameter: `{0}`' -f $parameter.name $paramIdentifier = ('#{0}' -f $paramHeader.TrimStart('#').Trim().ToLower()) -replace '[:|`]' -replace ' ', '-' From 092c3b21030cae8a3d8f1c67c05564a31866d32b Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 16:30:22 +0200 Subject: [PATCH 4/8] Reintro non-nullable due to arm bug? --- avm/res/cognitive-services/account/README.md | 3 ++- avm/res/cognitive-services/account/main.bicep | 5 +++-- avm/res/cognitive-services/account/main.json | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 2ba8b35700..19b14922ec 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1325,7 +1325,8 @@ Optional. Tags to be applied on all resources/resource groups in this deployment 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 -- Allowed: `[Disabled, Enabled]` +- Default: `''` +- Allowed: `['', Disabled, Enabled]` ### Parameter: `restore` diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 2518d58f2e..c60bcf9102 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -62,10 +62,11 @@ param diagnosticSettings diagnosticSettingType @description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') @allowed([ + '' 'Enabled' 'Disabled' ]) -param publicNetworkAccess string? +param publicNetworkAccess string = '' @description('Conditional. Subdomain name used for token-based authentication. Required if \'networkAcls\' or \'privateEndpoints\' are set.') param customSubDomainName string? @@ -207,7 +208,7 @@ resource cognitiveService 'Microsoft.CognitiveServices/accounts@2022-12-01' = { virtualNetworkRules: contains(networkAcls, 'virtualNetworkRules') ? networkAcls.virtualNetworkRules : [] ipRules: contains(networkAcls, 'ipRules') ? networkAcls.ipRules : [] } : null - publicNetworkAccess: publicNetworkAccess ?? (!empty(privateEndpoints) && empty(networkAcls) ? 'Disabled' : null) + publicNetworkAccess: !empty(publicNetworkAccess) ? any(publicNetworkAccess) : (!empty(privateEndpoints) && empty(networkAcls) ? 'Disabled' : null) allowedFqdnList: allowedFqdnList apiProperties: apiProperties disableLocalAuth: disableLocalAuth diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index ebd16d78e1..cd2aa4a61f 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.21.1.54444", - "templateHash": "8018230936247253236" + "templateHash": "6266103770814888437" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -503,8 +503,9 @@ }, "publicNetworkAccess": { "type": "string", - "nullable": true, + "defaultValue": "", "allowedValues": [ + "", "Enabled", "Disabled" ], @@ -728,7 +729,7 @@ "properties": { "customSubDomainName": "[parameters('customSubDomainName')]", "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('defaultAction', if(contains(parameters('networkAcls'), 'defaultAction'), parameters('networkAcls').defaultAction, null()), 'virtualNetworkRules', if(contains(parameters('networkAcls'), 'virtualNetworkRules'), parameters('networkAcls').virtualNetworkRules, createArray()), 'ipRules', if(contains(parameters('networkAcls'), 'ipRules'), parameters('networkAcls').ipRules, createArray())), null())]", - "publicNetworkAccess": "[coalesce(parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", "allowedFqdnList": "[parameters('allowedFqdnList')]", "apiProperties": "[parameters('apiProperties')]", "disableLocalAuth": "[parameters('disableLocalAuth')]", From c6c1073128a1bfe53808e40fd844fee5f10c0a36 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 16:35:02 +0200 Subject: [PATCH 5/8] Test with alternate service implementation --- avm/res/cognitive-services/account/main.bicep | 6 ++---- avm/res/cognitive-services/account/main.json | 8 ++++++-- avm/res/key-vault/vault/main.bicep | 6 ++---- avm/res/key-vault/vault/main.json | 8 ++++++-- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index c60bcf9102..24e492a2d8 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -267,10 +267,8 @@ resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSetti module cognitiveService_privateEndpoints '../../network/private-endpoint/main.bicep' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-CognitiveService-PrivateEndpoint-${index}' params: { - groupIds: contains(privateEndpoint, 'service') ? [ - privateEndpoint.service - ] : [ - 'account' + groupIds: [ + privateEndpoint.?service ?? 'account' ] name: privateEndpoint.?name ?? 'pe-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.service}-${index}' serviceResourceId: cognitiveService.id diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index cd2aa4a61f..27b9dd18c2 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.21.1.54444", - "templateHash": "6266103770814888437" + "templateHash": "4518990608215843089" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -818,7 +818,11 @@ }, "mode": "Incremental", "parameters": { - "groupIds": "[if(contains(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), createObject('value', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service)), createObject('value', createArray('account')))]", + "groupIds": { + "value": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')]" + ] + }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index cb5dd2d011..80c6e7c6d1 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -245,10 +245,8 @@ module keyVault_keys 'key/main.bicep' = [for (key, index) in (keys ?? []): { module keyVault_privateEndpoints '../../network/private-endpoint/main.bicep' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-KeyVault-PrivateEndpoint-${index}' params: { - groupIds: contains(privateEndpoint, 'service') ? [ - privateEndpoint.service - ] : [ - 'vault' + groupIds: [ + privateEndpoint.?service ?? 'vault' ] name: privateEndpoint.?name ?? 'pe-${last(split(keyVault.id, '/'))}-${privateEndpoint.service}-${index}' serviceResourceId: keyVault.id diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index c02b55da2d..fa35ce7e38 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "9181741770760472596" + "templateHash": "9844480828749170058" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -1366,7 +1366,11 @@ }, "mode": "Incremental", "parameters": { - "groupIds": "[if(contains(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), createObject('value', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service)), createObject('value', createArray('vault')))]", + "groupIds": { + "value": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')]" + ] + }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, From 090e233461ca69b2bad3d5c905e5d771376eb03e Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 16:40:09 +0200 Subject: [PATCH 6/8] Aligned with latest schema --- avm/res/cognitive-services/account/main.bicep | 6 +++--- avm/res/key-vault/vault/main.bicep | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 24e492a2d8..6a305ce962 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -426,10 +426,10 @@ type privateEndpointType = { customNetworkInterfaceName: string? @description('Optional. Specify the type of lock.') - lock: ('CanNotDelete' | 'ReadOnly' | '')? + lock: lockType? @description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') - roleAssignments: roleAssignmentType[]? + roleAssignments: roleAssignmentType? @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? @@ -437,7 +437,7 @@ type privateEndpointType = { @description('Optional. Manual PrivateLink Service Connections.') manualPrivateLinkServiceConnections: array? - @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') + @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index 80c6e7c6d1..fd86118813 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -415,7 +415,7 @@ type privateEndpointType = { @description('Optional. Manual PrivateLink Service Connections.') manualPrivateLinkServiceConnections: array? - @description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') + @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? From 65c80d848d9aa0b5faeb42f00bddc7267d241972 Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 16:54:00 +0200 Subject: [PATCH 7/8] Adjusted another ref --- avm/res/cognitive-services/account/README.md | 13 ++++++------- avm/res/cognitive-services/account/main.bicep | 2 +- avm/res/cognitive-services/account/main.json | 18 +++++------------- avm/res/key-vault/vault/README.md | 4 ++-- avm/res/key-vault/vault/main.bicep | 2 +- avm/res/key-vault/vault/main.json | 6 +++--- 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 19b14922ec..4ffedf0477 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1163,15 +1163,15 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | No | array | Optional. Application security groups in which the private endpoint IP configuration is included. | | [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | No | array | Optional. Custom DNS configurations. | | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | No | string | Optional. The custom name of the network interface attached to the private endpoint. | -| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | No | bool | Optional. Enable telemetry via a Globally Unique Identifier (GUID). | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | No | bool | Optional. Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | No | array | Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | | [`location`](#parameter-privateendpointslocation) | No | string | Optional. The location to deploy the private endpoint to. | -| [`lock`](#parameter-privateendpointslock) | No | string | Optional. Specify the type of lock. | +| [`lock`](#parameter-privateendpointslock) | No | | Optional. Specify the type of lock. | | [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | No | array | Optional. Manual PrivateLink Service Connections. | | [`name`](#parameter-privateendpointsname) | No | string | Optional. The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | No | string | Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | No | array | Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | -| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | array | Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | No | | Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | | [`service`](#parameter-privateendpointsservice) | No | string | Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | Yes | string | Required. Resource ID of the subnet where the endpoint needs to be created. | | [`tags`](#parameter-privateendpointstags) | No | object | Optional. Tags to be applied on all resources/resource groups in this deployment. | @@ -1213,7 +1213,7 @@ Optional. The custom name of the network interface attached to the private endpo ### Parameter: `privateEndpoints.enableTelemetry` -Optional. Enable telemetry via a Globally Unique Identifier (GUID). +Optional. Enable/Disable usage telemetry for module. - Required: No - Type: bool @@ -1261,8 +1261,7 @@ Optional. The location to deploy the private endpoint to. Optional. Specify the type of lock. - Required: No -- Type: string -- Allowed: `[, CanNotDelete, ReadOnly]` +- Type: ### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` @@ -1297,7 +1296,7 @@ Optional. The private DNS zone groups to associate the private endpoint with. A Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. - Required: No -- Type: array +- Type: ### Parameter: `privateEndpoints.service` diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 6a305ce962..bc00d2117e 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -270,7 +270,7 @@ module cognitiveService_privateEndpoints '../../network/private-endpoint/main.bi groupIds: [ privateEndpoint.?service ?? 'account' ] - name: privateEndpoint.?name ?? 'pe-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.service}-${index}' + name: privateEndpoint.?name ?? 'pe-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'vault'}-${index}' serviceResourceId: cognitiveService.id subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 27b9dd18c2..2177b9c3dd 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.21.1.54444", - "templateHash": "4518990608215843089" + "templateHash": "12123303560474072139" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -298,22 +298,14 @@ } }, "lock": { - "type": "string", - "allowedValues": [ - "", - "CanNotDelete", - "ReadOnly" - ], + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { "description": "Optional. Specify the type of lock." } }, "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, + "$ref": "#/definitions/roleAssignmentType", "nullable": true, "metadata": { "description": "Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." @@ -337,7 +329,7 @@ "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." + "description": "Optional. Enable/Disable usage telemetry for module." } } } @@ -824,7 +816,7 @@ ] }, "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" }, "serviceResourceId": { "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 8395845f86..01226930ec 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -1262,7 +1262,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | No | array | Optional. Application security groups in which the private endpoint IP configuration is included. | | [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | No | array | Optional. Custom DNS configurations. | | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | No | string | Optional. The custom name of the network interface attached to the private endpoint. | -| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | No | bool | Optional. Enable telemetry via a Globally Unique Identifier (GUID). | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | No | bool | Optional. Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | No | array | Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | | [`location`](#parameter-privateendpointslocation) | No | string | Optional. The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | No | | Optional. Specify the type of lock. | @@ -1312,7 +1312,7 @@ Optional. The custom name of the network interface attached to the private endpo ### Parameter: `privateEndpoints.enableTelemetry` -Optional. Enable telemetry via a Globally Unique Identifier (GUID). +Optional. Enable/Disable usage telemetry for module. - Required: No - Type: bool diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index fd86118813..feb7639f56 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -248,7 +248,7 @@ module keyVault_privateEndpoints '../../network/private-endpoint/main.bicep' = [ groupIds: [ privateEndpoint.?service ?? 'vault' ] - name: privateEndpoint.?name ?? 'pe-${last(split(keyVault.id, '/'))}-${privateEndpoint.service}-${index}' + name: privateEndpoint.?name ?? 'pe-${last(split(keyVault.id, '/'))}-${privateEndpoint.?service ?? 'vault'}-${index}' serviceResourceId: keyVault.id subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: enableTelemetry diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index fa35ce7e38..08fda2ef01 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "9844480828749170058" + "templateHash": "167861790396816165" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -329,7 +329,7 @@ "type": "bool", "nullable": true, "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." + "description": "Optional. Enable/Disable usage telemetry for module." } } } @@ -1372,7 +1372,7 @@ ] }, "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pe-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" }, "serviceResourceId": { "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" From 95a695832f8444657e33a0f1e35a77d7ebe510cd Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Wed, 27 Sep 2023 18:37:13 +0200 Subject: [PATCH 8/8] Confirmed test --- avm/utilities/tools/Test-ModuleLocally.ps1 | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/avm/utilities/tools/Test-ModuleLocally.ps1 b/avm/utilities/tools/Test-ModuleLocally.ps1 index a920b3e253..b062b1d897 100644 --- a/avm/utilities/tools/Test-ModuleLocally.ps1 +++ b/avm/utilities/tools/Test-ModuleLocally.ps1 @@ -27,6 +27,9 @@ Optional. A switch parameter that triggers the validation of the module only wit .PARAMETER SkipParameterFileTokens Optional. A switch parameter that enables you to skip the search for local custom parameter file tokens. +.PARAMETER AdditionalParameters +Optional. Additional parameters you can provide with the deployment. E.g. @{ resourceGroupName = 'myResourceGroup' } + .PARAMETER AdditionalTokens Optional. A hashtable parameter that contains custom tokens to be replaced in the paramter files for deployment @@ -153,6 +156,9 @@ function Test-ModuleLocally { [Parameter(Mandatory = $false)] [Psobject] $ValidateOrDeployParameters = @{}, + [Parameter(Mandatory = $false)] + [hashtable] $AdditionalParameters = @{}, + [Parameter(Mandatory = $false)] [hashtable] $AdditionalTokens = @{}, @@ -173,6 +179,7 @@ function Test-ModuleLocally { Write-Verbose "Running local tests for [$ModuleName]" # Load Tokens Converter Scripts . (Join-Path $utilitiesFolderPath 'pipelines' 'sharedScripts' 'tokenReplacement' 'Convert-TokensInFileList.ps1') + . (Join-Path $utilitiesFolderPath 'pipelines' 'sharedScripts' 'Get-LocallyReferencedFileList.ps1') # Load Modules Validation / Deployment Scripts . (Join-Path $utilitiesFolderPath 'pipelines' 'e2eValidation' 'resourceDeployment' 'New-TemplateDeployment.ps1') . (Join-Path $utilitiesFolderPath 'pipelines' 'e2eValidation' 'resourceDeployment' 'Test-TemplateDeployment.ps1') @@ -194,6 +201,12 @@ function Test-ModuleLocally { Tokens = @{} } + # Add any additional file that may contain tokens + foreach ($testFilePath in $moduleTestFiles) { + $tokenConfiguration.FilePathList += (Get-LocallyReferencedFileList -FilePath $testFilePath) + } + $tokenConfiguration.FilePathList = $tokenConfiguration.FilePathList | Sort-Object -Unique + # Add other template files as they may contain the 'moduleVersion' $moduleRoot = Split-Path $TemplateFilePath $tokenConfiguration.FilePathList += (Get-ChildItem -Path $moduleRoot -Recurse -File).FullName | Where-Object { $_ -match '.+(main.json|main.bicep)$' } @@ -253,12 +266,13 @@ function Test-ModuleLocally { # Deployment & Validation Testing # ------------------------------- $functionInput = @{ - TemplateFilePath = $TemplateFilePath - location = $ValidateOrDeployParameters.Location - resourceGroupName = $ValidateOrDeployParameters.ResourceGroupName - subscriptionId = $ValidateOrDeployParameters.SubscriptionId - managementGroupId = $ValidateOrDeployParameters.ManagementGroupId - Verbose = $true + TemplateFilePath = $TemplateFilePath + location = $ValidateOrDeployParameters.Location + resourceGroupName = $ValidateOrDeployParameters.ResourceGroupName + subscriptionId = $ValidateOrDeployParameters.SubscriptionId + managementGroupId = $ValidateOrDeployParameters.ManagementGroupId + additionalParameters = $additionalParameters + Verbose = $true } try {