diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index c14e60d3e1..4ffedf0477 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", @@ -876,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` @@ -932,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` @@ -1142,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` @@ -1169,15 +1163,16 @@ 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'. | -| [`service`](#parameter-privateendpointsservice) | Yes | string | Required. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`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. | @@ -1218,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 @@ -1266,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` @@ -1283,6 +1277,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. @@ -1295,13 +1296,13 @@ 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` -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` @@ -1421,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 d015ce1a55..bc00d2117e 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -69,7 +69,7 @@ param diagnosticSettings diagnosticSettingType 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 +84,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 +102,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 +111,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,7 +202,7 @@ 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 : [] @@ -221,10 +221,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 } } @@ -268,14 +268,15 @@ module cognitiveService_privateEndpoints '../../network/private-endpoint/main.bi name: '${uniqueString(deployment().name, location)}-CognitiveService-PrivateEndpoint-${index}' params: { groupIds: [ - privateEndpoint.service + 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 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 +393,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[]? @@ -422,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? @@ -433,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/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 72df1d85a1..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": "10343365646392943955" + "templateHash": "12123303560474072139" }, "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": { @@ -290,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'." @@ -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." } } } @@ -507,7 +507,7 @@ }, "customSubDomainName": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." } @@ -539,21 +539,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." } @@ -580,7 +580,7 @@ }, "migrationToken": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Resource migration token." } @@ -601,7 +601,7 @@ }, "userOwnedStorage": { "type": "array", - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. The storage accounts for this resource." } @@ -719,17 +719,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()))]", "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": [ @@ -812,11 +812,11 @@ "parameters": { "groupIds": { "value": [ - "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service]" + "[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()))]" + "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'))]" @@ -833,6 +833,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 +869,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 +989,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 +1014,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 +1049,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 +1122,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 +1193,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..01226930ec 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", @@ -1027,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` @@ -1205,7 +1202,6 @@ Specifies if the vault is enabled for a template deployment. All keys to create. - Required: No - Type: array -- Default: `[]` ### Parameter: `location` @@ -1266,15 +1262,16 @@ 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. | | [`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. | @@ -1315,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 @@ -1379,6 +1376,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 +1399,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` @@ -1495,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` @@ -1517,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 bd6bcf09c1..feb7639f56 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 @@ -246,14 +246,15 @@ module keyVault_privateEndpoints '../../network/private-endpoint/main.bicep' = [ name: '${uniqueString(deployment().name, location)}-KeyVault-PrivateEndpoint-${index}' params: { groupIds: [ - privateEndpoint.service + 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 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 +371,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[]? @@ -411,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? }[]? diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 6d18b1881b..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": "906532672506379950" + "templateHash": "167861790396816165" }, "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": { @@ -321,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." } } } @@ -371,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." } @@ -496,7 +504,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } @@ -519,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)]" } } ], @@ -544,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": { @@ -672,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.", @@ -692,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." } @@ -702,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", @@ -789,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.", @@ -878,7 +896,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } @@ -1022,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", @@ -1034,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#", @@ -1058,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.", @@ -1147,7 +1165,7 @@ }, "tags": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Resource tags." } @@ -1161,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." } @@ -1188,7 +1206,7 @@ }, "keyOps": { "type": "array", - "defaultValue": [], + "nullable": true, "allowedValues": [ "decrypt", "encrypt", @@ -1204,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." } @@ -1230,7 +1248,7 @@ }, "rotationPolicy": { "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { "description": "Optional. Key rotation policy properties object." } @@ -1269,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" @@ -1350,11 +1368,11 @@ "parameters": { "groupIds": { "value": [ - "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service]" + "[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()))]" + "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'))]" @@ -1371,6 +1389,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 +1425,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 +1545,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 +1570,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 +1605,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 +1678,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 +1749,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/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." } 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..4360adbe94 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -198,8 +198,21 @@ 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 + } + + $required = -not $defaultValue -and -not $parameter.nullable $rawAllowedValues = $parameter.allowedValues } @@ -1065,12 +1078,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 ############################ 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 {