diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ac3027914ee..5a6abd02d42 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,14 +17,14 @@ ] } }, - "postCreateCommand": "npm install -g prettier && dotnet tool install -g Azure.Bicep.RegistryModuleTool", + "postCreateCommand": "npm install -g prettier && dotnet tool install -g Azure.Bicep.RegistryModuleTool && pwsh -C Install-Module Az.Accounts -Repository PSGallery -Force && pwsh -C Install-Module Az.Resources -Repository PSGallery -Force && pwsh -C Install-Module Az.KeyVault -Repository PSGallery -Force", "postStartCommand": "az bicep install", "remoteEnv": { "PATH": "${containerEnv:PATH}:/home/node/.dotnet/tools:/home/node/.azure/bin" }, "features": { "azure-cli": "latest", - "dotnet": "7.0", + "dotnet": "8.0", "ghcr.io/devcontainers/features/node:1": {}, "ghcr.io/devcontainers/features/powershell:1": {} } diff --git a/avm/res/automation/automation-account/README.md b/avm/res/automation/automation-account/README.md index 43a4f43ccfd..7453918030c 100644 --- a/avm/res/automation/automation-account/README.md +++ b/avm/res/automation/automation-account/README.md @@ -233,6 +233,18 @@ module automationAccount 'br/public:avm/res/automation/automation-account:' + ] + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } { privateDnsZoneResourceIds: [ '' @@ -467,6 +479,18 @@ module automationAccount 'br/public:avm/res/automation/automation-account:" + ], + "service": "Webhook", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, { "privateDnsZoneResourceIds": [ "" @@ -1420,7 +1444,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | Parameter | Type | Description | | :-- | :-- | :-- | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | **Optional parameters** @@ -1432,9 +1456,10 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | @@ -1443,7 +1468,7 @@ Configuration details for private endpoints. For security reasons, it is recomme ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". - Required: Yes - Type: string @@ -1561,6 +1586,13 @@ A private ip address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1604,12 +1636,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1905,7 +1937,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | | `res/operational-insights/workspace/linked-service` | Local reference | -| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | | `br/public:avm/res/operations-management/solution:0.1.0` | Remote reference | ## Data Collection diff --git a/avm/res/automation/automation-account/main.bicep b/avm/res/automation/automation-account/main.bicep index 512aa2354a3..9db1af88c2d 100644 --- a/avm/res/automation/automation-account/main.bicep +++ b/avm/res/automation/automation-account/main.bicep @@ -328,34 +328,45 @@ resource automationAccount_diagnosticSettings 'Microsoft.Insights/diagnosticSett scope: automationAccount }] -module automationAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module automationAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-automationAccount-PrivateEndpoint-${index}' params: { - privateLinkServiceConnections: [ + name: privateEndpoint.?name ?? 'pep-${last(split(automationAccount.id, '/'))}-${privateEndpoint.service}-${index}' + privateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections != true ? [ { - name: name + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(automationAccount.id, '/'))}-${privateEndpoint.service}-${index}' properties: { privateLinkServiceId: automationAccount.id groupIds: [ - privateEndpoint.?service ?? 'automationaccount' + privateEndpoint.service ] } } - ] - name: privateEndpoint.?name ?? 'pep-${last(split(automationAccount.id, '/'))}-${privateEndpoint.?service ?? privateEndpoint.service}-${index}' + ] : null + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(automationAccount.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: automationAccount.id + groupIds: [ + privateEndpoint.service + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName - enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry } }] @@ -438,7 +449,7 @@ 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".') + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') service: string @description('Required. Resource ID of the subnet where the endpoint needs to be created.') @@ -450,6 +461,13 @@ type privateEndpointType = { @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { @description('Required. Fqdn that resolves to private endpoint ip address.') @@ -492,9 +510,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/automation/automation-account/main.json b/avm/res/automation/automation-account/main.json index 0a24cab4468..feb3919fc8e 100644 --- a/avm/res/automation/automation-account/main.json +++ b/avm/res/automation/automation-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "3223894986476226816" + "templateHash": "17457652611185300575" }, "name": "Automation Accounts", "description": "This module deploys an Azure Automation Account.", @@ -149,7 +149,7 @@ "service": { "type": "string", "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\"." } }, "subnetResourceId": { @@ -175,6 +175,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -283,13 +298,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -2310,25 +2318,17 @@ }, "mode": "Incremental", "parameters": { - "privateLinkServiceConnections": { - "value": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.Automation/automationAccounts', parameters('name'))]", - "groupIds": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'automationaccount')]" - ] - } - } - ] - }, "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Automation/automationAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Automation/automationAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, "location": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, @@ -2347,9 +2347,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -2361,9 +2358,6 @@ }, "customNetworkInterfaceName": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" } }, "template": { @@ -2373,8 +2367,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -2423,7 +2417,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -2501,7 +2495,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -2604,7 +2598,7 @@ "fqdn": { "type": "string", "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -2613,7 +2607,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -2739,7 +2733,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2844,8 +2838,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18168683629401652671" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -2956,6 +2950,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/automation/automation-account/tests/e2e/max/dependencies.bicep b/avm/res/automation/automation-account/tests/e2e/max/dependencies.bicep index 77af000af6c..403211cdb75 100644 --- a/avm/res/automation/automation-account/tests/e2e/max/dependencies.bicep +++ b/avm/res/automation/automation-account/tests/e2e/max/dependencies.bicep @@ -22,7 +22,19 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { { name: 'defaultSubnet' properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + } + } + { + name: 'custom-private-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + } + } + { + name: 'custom-private-subnet-2' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 2) } } ] @@ -50,9 +62,15 @@ resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018- location: location } -@description('The resource ID of the created Virtual Network Subnet.') +@description('The resource ID of the created Virtual Network Default Subnet.') output subnetResourceId string = virtualNetwork.properties.subnets[0].id +@description('The resource ID of the 2nd created Virtual Network Subnet.') +output customSubnet1ResourceId string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the 3rd created Virtual Network Subnet.') +output customSubnet2ResourceId string = virtualNetwork.properties.subnets[2].id + @description('The principal ID of the created Managed Identity.') output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/automation/automation-account/tests/e2e/max/main.test.bicep b/avm/res/automation/automation-account/tests/e2e/max/main.test.bicep index 8067995a678..0c9b5a710d7 100644 --- a/avm/res/automation/automation-account/tests/e2e/max/main.test.bicep +++ b/avm/res/automation/automation-account/tests/e2e/max/main.test.bicep @@ -102,7 +102,19 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' nestedDependencies.outputs.privateDNSZoneResourceId ] service: 'Webhook' - subnetResourceId: nestedDependencies.outputs.subnetResourceId + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + service: 'Webhook' + subnetResourceId: nestedDependencies.outputs.customSubnet2ResourceId tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' @@ -114,7 +126,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' nestedDependencies.outputs.privateDNSZoneResourceId ] service: 'DSCAndHybridWorker' - subnetResourceId: nestedDependencies.outputs.subnetResourceId + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' @@ -256,4 +268,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep index fbaee4ef113..d2bbfb2033a 100644 --- a/avm/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep @@ -242,4 +242,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/automation/automation-account/version.json b/avm/res/automation/automation-account/version.json index 83083db6945..c177b1bb58b 100644 --- a/avm/res/automation/automation-account/version.json +++ b/avm/res/automation/automation-account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.3", "pathFilters": [ "./main.json" ] diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index b7a08c4390f..1ea59e9346d 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -231,7 +231,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { { fqdn: 'abc.batch.com' ipAddresses: [ - '10.0.0.10' + '10.0.16.10' ] } ] @@ -241,7 +241,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { properties: { groupId: 'batchAccount' memberName: 'batchAccount' - privateIPAddress: '10.0.0.10' + privateIPAddress: '10.0.16.10' } } ] @@ -260,6 +260,31 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { roleDefinitionIdOrName: '' } ] + service: 'batchAccount' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'batchAccount' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'nodeManagement' subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -366,7 +391,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { { "fqdn": "abc.batch.com", "ipAddresses": [ - "10.0.0.10" + "10.0.16.10" ] } ], @@ -376,7 +401,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "properties": { "groupId": "batchAccount", "memberName": "batchAccount", - "privateIPAddress": "10.0.0.10" + "privateIPAddress": "10.0.16.10" } } ], @@ -395,6 +420,31 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "roleDefinitionIdOrName": "" } ], + "service": "batchAccount", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "service": "batchAccount", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "service": "nodeManagement", "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -482,6 +532,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { privateDnsZoneResourceIds: [ '' ] + service: 'batchAccount' subnetResourceId: '' } ] @@ -549,6 +600,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = { "privateDnsZoneResourceIds": [ "" ], + "service": "batchAccount", "subnetResourceId": "" } ] @@ -1022,6 +1074,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | Parameter | Type | Description | | :-- | :-- | :-- | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | **Optional parameters** @@ -1033,16 +1086,23 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | +### Parameter: `privateEndpoints.service` + +The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". + +- Required: Yes +- Type: string + ### Parameter: `privateEndpoints.subnetResourceId` Resource ID of the subnet where the endpoint needs to be created. @@ -1156,6 +1216,13 @@ A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1199,12 +1266,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1316,13 +1383,6 @@ The principal type of the assigned principal ID. ] ``` -### Parameter: `privateEndpoints.service` - -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". - -- Required: No -- Type: string - ### Parameter: `privateEndpoints.tags` Tags to be applied on all resources/resource groups in this deployment. @@ -1481,7 +1541,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/batch/batch-account/main.bicep b/avm/res/batch/batch-account/main.bicep index 4326c505b06..8d7cbddb361 100644 --- a/avm/res/batch/batch-account/main.bicep +++ b/avm/res/batch/batch-account/main.bicep @@ -201,21 +201,33 @@ resource batchAccount_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@ scope: batchAccount }] -module batchAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module batchAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-BatchAccount-PrivateEndpoint-${index}' params: { - privateLinkServiceConnections: [ + name: privateEndpoint.?name ?? 'pep-${last(split(batchAccount.id, '/'))}-${privateEndpoint.service}-${index}' + privateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections != true ? [ { - name: name + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(batchAccount.id, '/'))}-${privateEndpoint.service}-${index}' properties: { privateLinkServiceId: batchAccount.id groupIds: [ - privateEndpoint.?service ?? 'batchAccount' + privateEndpoint.service ] } } - ] - name: privateEndpoint.?name ?? 'pep-${last(split(batchAccount.id, '/'))}-${privateEndpoint.?service ?? 'batchAccount'}-${index}' + ] : null + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(batchAccount.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: batchAccount.id + groupIds: [ + privateEndpoint.service + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -224,7 +236,6 @@ module batchAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -339,8 +350,8 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') - service: string? + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') + service: string @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string @@ -351,6 +362,13 @@ type privateEndpointType = { @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { @description('Required. Fqdn that resolves to private endpoint IP address.') @@ -393,9 +411,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/batch/batch-account/main.json b/avm/res/batch/batch-account/main.json index 3731161e53c..925fe851308 100644 --- a/avm/res/batch/batch-account/main.json +++ b/avm/res/batch/batch-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "2397736043296643387" + "templateHash": "11102129881431176996" }, "name": "Batch Accounts", "description": "This module deploys a Batch Account.", @@ -220,9 +220,8 @@ }, "service": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\"." } }, "subnetResourceId": { @@ -248,6 +247,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -357,13 +371,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -826,22 +833,11 @@ }, "mode": "Incremental", "parameters": { - "privateLinkServiceConnections": { - "value": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.Batch/batchAccounts', parameters('name'))]", - "groupIds": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'batchAccount')]" - ] - } - } - ] - }, "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Batch/batchAccounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'batchAccount'), copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Batch/batchAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Batch/batchAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Batch/batchAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Batch/batchAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Batch/batchAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -866,9 +862,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -889,8 +882,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -939,7 +932,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -1017,7 +1010,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -1120,7 +1113,7 @@ "fqdn": { "type": "string", "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -1129,7 +1122,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -1255,7 +1248,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1360,8 +1353,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18168683629401652671" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1472,6 +1465,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/batch/batch-account/tests/e2e/max/dependencies.bicep b/avm/res/batch/batch-account/tests/e2e/max/dependencies.bicep index 462e8a5f27f..a0acbbc3024 100644 --- a/avm/res/batch/batch-account/tests/e2e/max/dependencies.bicep +++ b/avm/res/batch/batch-account/tests/e2e/max/dependencies.bicep @@ -34,7 +34,19 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { { name: 'defaultSubnet' properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + } + } + { + name: 'custom-private-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + } + } + { + name: 'custom-private-subnet-2' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 2) } } ] @@ -62,8 +74,14 @@ resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018- location: location } -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id +@description('The resource ID of the created Virtual Network Default Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the 2nd created Virtual Network Subnet.') +output customSubnet1ResourceId string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the 3rd created Virtual Network Subnet.') +output customSubnet2ResourceId string = virtualNetwork.properties.subnets[2].id @description('The principal ID of the created Managed Identity.') output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep b/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep index 1a31a13cce6..85afc629caf 100644 --- a/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep +++ b/avm/res/batch/batch-account/tests/e2e/max/main.test.bicep @@ -87,7 +87,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId ] - subnetResourceId: nestedDependencies.outputs.subnetResourceId + service: 'batchAccount' + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' @@ -111,7 +112,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' properties: { groupId: 'batchAccount' memberName: 'batchAccount' - privateIPAddress: '10.0.0.10' + privateIPAddress: '10.0.16.10' } } ] @@ -119,11 +120,35 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' { fqdn: 'abc.batch.com' ipAddresses: [ - '10.0.0.10' + '10.0.16.10' ] } ] } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + service: 'batchAccount' + subnetResourceId: nestedDependencies.outputs.customSubnet2ResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + service: 'nodeManagement' + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } ] networkProfile: { accountAccess: { @@ -166,4 +191,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep index f66d2bac7a2..b01e34b2d01 100644 --- a/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/batch/batch-account/tests/e2e/waf-aligned/main.test.bicep @@ -86,6 +86,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId ] + service: 'batchAccount' subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] @@ -100,4 +101,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/batch/batch-account/version.json b/avm/res/batch/batch-account/version.json index c177b1bb58b..a8eda31021f 100644 --- a/avm/res/batch/batch-account/version.json +++ b/avm/res/batch/batch-account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.5", "pathFilters": [ "./main.json" ] diff --git a/avm/res/cache/redis/README.md b/avm/res/cache/redis/README.md index 1b8ef80cda2..11b99c963db 100644 --- a/avm/res/cache/redis/README.md +++ b/avm/res/cache/redis/README.md @@ -156,6 +156,12 @@ module redis 'br/public:avm/res/cache/redis:' = { Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } ] redisVersion: '6' roleAssignments: [ @@ -278,6 +284,12 @@ module redis 'br/public:avm/res/cache/redis:' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "" } ] }, @@ -839,14 +851,15 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `privateEndpoints.subnetResourceId` @@ -962,6 +975,13 @@ A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1005,12 +1025,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1124,7 +1144,7 @@ The principal type of the assigned principal ID. ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". - Required: No - Type: string @@ -1371,7 +1391,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Notes diff --git a/avm/res/cache/redis/main.bicep b/avm/res/cache/redis/main.bicep index de470572480..38ffba3aabd 100644 --- a/avm/res/cache/redis/main.bicep +++ b/avm/res/cache/redis/main.bicep @@ -213,12 +213,13 @@ resource redis_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04- scope: redis }] -module redis_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module redis_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-KeyVault-PrivateEndpoint-${index}' params: { + name: privateEndpoint.?name ?? 'pep-${last(split(redis.id, '/'))}-${privateEndpoint.?service ?? 'redisCache'}-${index}' privateLinkServiceConnections: [ { - name: name + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(redis.id, '/'))}-${privateEndpoint.?service ?? 'redisCache'}-${index}' properties: { privateLinkServiceId: redis.id groupIds: [ @@ -227,7 +228,18 @@ module redis_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' } } ] - name: privateEndpoint.?name ?? 'pep-${last(split(redis.id, '/'))}-${privateEndpoint.?service ?? 'redisCache'}-${index}' + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(redis.id, '/'))}-${privateEndpoint.?service ?? 'redisCache'}-${index}' + properties: { + privateLinkServiceId: redis.id + groupIds: [ + privateEndpoint.?service ?? 'redisCache' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -236,7 +248,6 @@ module redis_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -289,14 +300,13 @@ type lockType = { }? type privateEndpointType = { - @description('Optional. The name of the private endpoint.') name: string? @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @description('Required. Resource ID of the subnet where the endpoint needs to be created.') @@ -308,6 +318,13 @@ type privateEndpointType = { @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { @description('Required. Fqdn that resolves to private endpoint IP address.') @@ -350,9 +367,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/cache/redis/main.json b/avm/res/cache/redis/main.json index 85d840b5725..9a90df4cd85 100644 --- a/avm/res/cache/redis/main.json +++ b/avm/res/cache/redis/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "16070478115038910597" + "templateHash": "798005420934456091" }, "name": "Redis Cache", "description": "This module deploys a Redis Cache.", @@ -84,7 +84,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." } }, "subnetResourceId": { @@ -110,6 +110,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -218,13 +233,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -770,10 +778,13 @@ }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Cache/redis', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisCache'), copyIndex()))]" + }, "privateLinkServiceConnections": { "value": [ { - "name": "[parameters('name')]", + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Cache/redis', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisCache'), copyIndex()))]", "properties": { "privateLinkServiceId": "[resourceId('Microsoft.Cache/redis', parameters('name'))]", "groupIds": [ @@ -783,9 +794,7 @@ } ] }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Cache/redis', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisCache'), copyIndex()))]" - }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Cache/redis', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisCache'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Cache/redis', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisCache')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -810,9 +819,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -833,8 +839,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -883,7 +889,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -961,7 +967,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -1064,7 +1070,7 @@ "fqdn": { "type": "string", "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -1073,7 +1079,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -1199,7 +1205,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1304,8 +1310,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18168683629401652671" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1416,6 +1422,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/cache/redis/tests/e2e/max/main.test.bicep b/avm/res/cache/redis/tests/e2e/max/main.test.bicep index 5ba333465dc..cc8bd7dde17 100644 --- a/avm/res/cache/redis/tests/e2e/max/main.test.bicep +++ b/avm/res/cache/redis/tests/e2e/max/main.test.bicep @@ -118,6 +118,12 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } ] redisVersion: '6' shardCount: 1 @@ -150,4 +156,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' resourceType: 'Redis Cache' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/cache/redis/tests/e2e/waf-aligned/main.test.bicep b/avm/res/cache/redis/tests/e2e/waf-aligned/main.test.bicep index 337a88e772a..1a0542d4a34 100644 --- a/avm/res/cache/redis/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/cache/redis/tests/e2e/waf-aligned/main.test.bicep @@ -112,4 +112,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' resourceType: 'Redis Cache' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/cache/redis/version.json b/avm/res/cache/redis/version.json index 7fa401bdf78..1c035df49f2 100644 --- a/avm/res/cache/redis/version.json +++ b/avm/res/cache/redis/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] -} +} \ No newline at end of file diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 2e5dc2db5dc..7829d5f201a 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -184,6 +184,12 @@ module account 'br/public:avm/res/cognitive-services/account:' = { Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } ] publicNetworkAccess: 'Disabled' roleAssignments: [ @@ -323,6 +329,12 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "" } ] }, @@ -1222,14 +1234,15 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `privateEndpoints.subnetResourceId` @@ -1345,6 +1358,13 @@ A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1388,12 +1408,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1507,7 +1527,7 @@ The principal type of the assigned principal ID. ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". - Required: No - Type: string @@ -1702,7 +1722,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 05149ac191b..55a51646ae9 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -265,12 +265,13 @@ resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSetti scope: cognitiveService }] -module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-CognitiveService-PrivateEndpoint-${index}' params: { + name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' privateLinkServiceConnections: [ { - name: name + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' properties: { privateLinkServiceId: cognitiveService.id groupIds: [ @@ -279,7 +280,18 @@ module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endp } } ] - name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -288,7 +300,6 @@ module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endp privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -406,7 +417,7 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @description('Required. Resource ID of the subnet where the endpoint needs to be created.') @@ -418,6 +429,13 @@ type privateEndpointType = { @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { @description('Required. Fqdn that resolves to private endpoint IP address.') @@ -455,14 +473,11 @@ type privateEndpointType = { lock: lockType @description('Optional. Array of role assignments to create.') - roleAssignments: roleAssignmentType? + roleAssignments: roleAssignmentType @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @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 97ad908e5bf..a45302ba9e4 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.25.53.49325", - "templateHash": "6619617132004799661" + "templateHash": "6670691272648355802" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -222,7 +222,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." } }, "subnetResourceId": { @@ -248,6 +248,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -345,7 +360,6 @@ }, "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", - "nullable": true, "metadata": { "description": "Optional. Array of role assignments to create." } @@ -357,13 +371,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -873,10 +880,13 @@ }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, "privateLinkServiceConnections": { "value": [ { - "name": "[parameters('name')]", + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]", "properties": { "privateLinkServiceId": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", "groupIds": [ @@ -886,9 +896,7 @@ } ] }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -913,9 +921,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -936,8 +941,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -986,7 +991,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -1064,7 +1069,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -1167,7 +1172,7 @@ "fqdn": { "type": "string", "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -1176,7 +1181,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -1302,7 +1307,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1407,8 +1412,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18168683629401652671" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1519,6 +1524,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } 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 e13f8afd9f2..c133cecb591 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 @@ -162,6 +162,12 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } ] } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } ] tags: { 'hidden-title': 'This is visible in the resource name' @@ -169,4 +175,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep index e349981b033..d115398bf16 100644 --- a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep @@ -79,4 +79,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + ] }] diff --git a/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep index e657ba486bb..3e79483631f 100644 --- a/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep @@ -68,4 +68,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } restrictOutboundNetworkAccess: false } + dependsOn: [ + nestedDependencies + ] }] diff --git a/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep index 241ca59ae41..f161025c181 100644 --- a/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep @@ -71,4 +71,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } restrictOutboundNetworkAccess: false } + dependsOn: [ + nestedDependencies + ] }] diff --git a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep index 41d53958caf..362a8ade162 100644 --- a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep @@ -102,4 +102,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' systemAssigned: true } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/cognitive-services/account/version.json b/avm/res/cognitive-services/account/version.json index c177b1bb58b..3f863a2bec9 100644 --- a/avm/res/cognitive-services/account/version.json +++ b/avm/res/cognitive-services/account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.4", "pathFilters": [ "./main.json" ] diff --git a/avm/res/container-registry/registry/README.md b/avm/res/container-registry/registry/README.md index 9c96fdf622e..12a6dca9309 100644 --- a/avm/res/container-registry/registry/README.md +++ b/avm/res/container-registry/registry/README.md @@ -36,8 +36,7 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using encryption with Customer-Managed-Key](#example-2-using-encryption-with-customer-managed-key) - [Using large parameter set](#example-3-using-large-parameter-set) -- [Using private endpoint](#example-4-using-private-endpoint) -- [WAF-aligned](#example-5-waf-aligned) +- [WAF-aligned](#example-4-waf-aligned) ### Example 1: _Using only defaults_ @@ -233,7 +232,6 @@ module registry 'br/public:avm/res/container-registry/registry:' = { privateDnsZoneResourceIds: [ '' ] - service: 'registry' subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -241,6 +239,12 @@ module registry 'br/public:avm/res/container-registry/registry:' = { Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } ] quarantinePolicyStatus: 'enabled' replications: [ @@ -372,13 +376,18 @@ module registry 'br/public:avm/res/container-registry/registry:' = { "privateDnsZoneResourceIds": [ "" ], - "service": "registry", "subnetResourceId": "", "tags": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "" } ] }, @@ -443,77 +452,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

-### Example 4: _Using private endpoint_ - -This instance deploys the module with a private endpoint. - - -

- -via Bicep module - -```bicep -module registry 'br/public:avm/res/container-registry/registry:' = { - name: '${uniqueString(deployment().name, resourceLocation)}-test-crrpe' - params: { - // Required parameters - name: 'crrpe001' - // Non-required parameters - acrSku: 'Premium' - location: '' - privateEndpoints: [ - { - privateDnsZoneResourceIds: [ - '' - ] - subnetResourceId: '' - } - ] - } -} -``` - -
-

- -

- -via JSON Parameter file - -```json -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - // Required parameters - "name": { - "value": "crrpe001" - }, - // Non-required parameters - "acrSku": { - "value": "Premium" - }, - "location": { - "value": "" - }, - "privateEndpoints": { - "value": [ - { - "privateDnsZoneResourceIds": [ - "" - ], - "subnetResourceId": "" - } - ] - } - } -} -``` - -
-

- -### Example 5: _WAF-aligned_ +### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1098,14 +1037,15 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | -| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `privateEndpoints.subnetResourceId` @@ -1133,19 +1073,19 @@ Custom DNS configurations. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint ip address. | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private ip addresses of the private endpoint. | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` -Fqdn that resolves to private endpoint ip address. +Fqdn that resolves to private endpoint IP address. - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` -A list of private ip addresses of the private endpoint. +A list of private IP addresses of the private endpoint. - Required: Yes - Type: array @@ -1198,7 +1138,7 @@ Properties of private endpoint IP configurations. | :-- | :-- | :-- | | [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | | [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | -| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private ip address obtained from the private endpoint's subnet. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | ### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` @@ -1216,11 +1156,18 @@ The member name of a group obtained from the remote resource that this private e ### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` -A private ip address obtained from the private endpoint's subnet. +A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1264,12 +1211,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1280,7 +1227,7 @@ The name of the private endpoint. ### Parameter: `privateEndpoints.privateDnsZoneGroupName` -The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. +The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. - Required: No - Type: string @@ -1383,7 +1330,7 @@ The principal type of the assigned principal ID. ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". - Required: No - Type: string @@ -1628,7 +1575,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.3.2` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/container-registry/registry/main.bicep b/avm/res/container-registry/registry/main.bicep index 8c33bc71545..05bd6d96d44 100644 --- a/avm/res/container-registry/registry/main.bicep +++ b/avm/res/container-registry/registry/main.bicep @@ -334,12 +334,13 @@ resource registry_roleAssignments 'Microsoft.Authorization/roleAssignments@2022- scope: registry }] -module registry_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.2' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module registry_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-registry-PrivateEndpoint-${index}' params: { + name: privateEndpoint.?name ?? 'pep-${last(split(registry.id, '/'))}-${privateEndpoint.?service ?? 'registry'}-${index}' privateLinkServiceConnections: [ { - name: name + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(registry.id, '/'))}-${privateEndpoint.?service ?? 'registry'}-${index}' properties: { privateLinkServiceId: registry.id groupIds: [ @@ -348,7 +349,18 @@ module registry_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3 } } ] - name: privateEndpoint.?name ?? 'pep-${last(split(registry.id, '/'))}-${privateEndpoint.?service ?? 'registry'}-${index}' + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(registry.id, '/'))}-${privateEndpoint.?service ?? 'registry'}-${index}' + properties: { + privateLinkServiceId: registry.id + groupIds: [ + privateEndpoint.?service ?? 'registry' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -357,7 +369,6 @@ module registry_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3 privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -433,24 +444,31 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string - @description('Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided.') + @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') privateDnsZoneGroupName: string? @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { - @description('Required. Fqdn that resolves to private endpoint ip address.') + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? - @description('Required. A list of private ip addresses of the private endpoint.') + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @@ -467,7 +485,7 @@ type privateEndpointType = { @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') memberName: string - @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') privateIPAddress: string } }[]? @@ -487,9 +505,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/container-registry/registry/main.json b/avm/res/container-registry/registry/main.json index fb6accc8373..e08259390f5 100644 --- a/avm/res/container-registry/registry/main.json +++ b/avm/res/container-registry/registry/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "3316618601179718411" + "templateHash": "9195818754355186204" }, "name": "Azure Container Registries (ACR)", "description": "This module deploys an Azure Container Registry (ACR).", @@ -150,7 +150,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." } }, "subnetResourceId": { @@ -163,7 +163,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." } }, "privateDnsZoneResourceIds": { @@ -176,6 +176,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -185,7 +200,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -194,7 +209,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -233,7 +248,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -284,13 +299,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -1402,10 +1410,13 @@ }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, "privateLinkServiceConnections": { "value": [ { - "name": "[parameters('name')]", + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]", "properties": { "privateLinkServiceId": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]", "groupIds": [ @@ -1415,9 +1426,7 @@ } ] }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" - }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -1442,9 +1451,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -1465,8 +1471,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -1515,7 +1521,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -1831,7 +1837,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1936,8 +1942,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18168683629401652671" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -2048,6 +2054,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/container-registry/registry/tests/e2e/encr/main.test.bicep b/avm/res/container-registry/registry/tests/e2e/encr/main.test.bicep index bf33665f09c..740e8c19d60 100644 --- a/avm/res/container-registry/registry/tests/e2e/encr/main.test.bicep +++ b/avm/res/container-registry/registry/tests/e2e/encr/main.test.bicep @@ -70,4 +70,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ] } } + dependsOn: [ + nestedDependencies + ] }] diff --git a/avm/res/container-registry/registry/tests/e2e/max/main.test.bicep b/avm/res/container-registry/registry/tests/e2e/max/main.test.bicep index 38d182fd5a4..6153fdefb52 100644 --- a/avm/res/container-registry/registry/tests/e2e/max/main.test.bicep +++ b/avm/res/container-registry/registry/tests/e2e/max/main.test.bicep @@ -94,7 +94,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' } privateEndpoints: [ { - service: 'registry' subnetResourceId: nestedDependencies.outputs.subnetResourceId privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId @@ -105,6 +104,12 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + { + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + } ] networkRuleSetIpRules: [ { @@ -165,4 +170,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/container-registry/registry/tests/e2e/pe/dependencies.bicep b/avm/res/container-registry/registry/tests/e2e/pe/dependencies.bicep deleted file mode 100644 index 0422180c419..00000000000 --- a/avm/res/container-registry/registry/tests/e2e/pe/dependencies.bicep +++ /dev/null @@ -1,49 +0,0 @@ -@description('Optional. The location to deploy resources to.') -param location string = resourceGroup().location - -@description('Required. The name of the Virtual Network to create.') -param virtualNetworkName string - -var addressPrefix = '10.0.0.0/16' - -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: 'defaultSubnet' - properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) - } - } - ] - } -} - -resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { - name: 'privatelink${environment().suffixes.acrLoginServer}' - location: 'global' - - resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { - name: '${virtualNetwork.name}-vnetlink' - location: 'global' - properties: { - virtualNetwork: { - id: virtualNetwork.id - } - registrationEnabled: false - } - } -} - -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id - -@description('The resource ID of the created Private DNS Zone.') -output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/container-registry/registry/tests/e2e/pe/main.test.bicep b/avm/res/container-registry/registry/tests/e2e/pe/main.test.bicep deleted file mode 100644 index f56d0c49e38..00000000000 --- a/avm/res/container-registry/registry/tests/e2e/pe/main.test.bicep +++ /dev/null @@ -1,64 +0,0 @@ -targetScope = 'subscription' - -metadata name = 'Using private endpoint' -metadata description = 'This instance deploys the module with a private endpoint.' - -// ========== // -// Parameters // -// ========== // - -@description('Optional. The name of the resource group to deploy for testing purposes.') -@maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-containerregistry.registries-${serviceShort}-rg' - -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - -@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'crrpe' - -@description('Optional. A token to inject into the name of each resource.') -param namePrefix string = '#_namePrefix_#' - -// ============ // -// Dependencies // -// ============ // - -// General resources -// ================= -resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: resourceGroupName - location: resourceLocation -} - -module nestedDependencies 'dependencies.bicep' = { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' - params: { - virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: resourceLocation - } -} - -// ============== // -// Test Execution // -// ============== // - -@batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - location: resourceLocation - acrSku: 'Premium' - privateEndpoints: [ - { - subnetResourceId: nestedDependencies.outputs.subnetResourceId - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] - } - ] - } -}] diff --git a/avm/res/container-registry/registry/tests/e2e/waf-aligned/main.test.bicep b/avm/res/container-registry/registry/tests/e2e/waf-aligned/main.test.bicep index 284f517de95..c046264a979 100644 --- a/avm/res/container-registry/registry/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/container-registry/registry/tests/e2e/waf-aligned/main.test.bicep @@ -94,4 +94,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/container-registry/registry/version.json b/avm/res/container-registry/registry/version.json index 83083db6945..1c035df49f2 100644 --- a/avm/res/container-registry/registry/version.json +++ b/avm/res/container-registry/registry/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] diff --git a/avm/res/data-factory/factory/README.md b/avm/res/data-factory/factory/README.md index 779fdc9c32a..c66b9c79f37 100644 --- a/avm/res/data-factory/factory/README.md +++ b/avm/res/data-factory/factory/README.md @@ -173,10 +173,16 @@ module factory 'br/public:avm/res/data-factory/factory:' = { ] subnetResourceId: '' tags: { - application: 'CARML' + application: 'AVM' 'hidden-title': 'This is visible in the resource name' } } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } ] roleAssignments: [ { @@ -313,9 +319,15 @@ module factory 'br/public:avm/res/data-factory/factory:' = { ], "subnetResourceId": "", "tags": { - "application": "CARML", + "application": "AVM", "hidden-title": "This is visible in the resource name" } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "" } ] }, @@ -893,14 +905,15 @@ Configuration Details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | -| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `privateEndpoints.subnetResourceId` @@ -928,19 +941,19 @@ Custom DNS configurations. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint ip address. | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private ip addresses of the private endpoint. | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` -Fqdn that resolves to private endpoint ip address. +Fqdn that resolves to private endpoint IP address. - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` -A list of private ip addresses of the private endpoint. +A list of private IP addresses of the private endpoint. - Required: Yes - Type: array @@ -993,7 +1006,7 @@ Properties of private endpoint IP configurations. | :-- | :-- | :-- | | [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | | [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | -| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private ip address obtained from the private endpoint's subnet. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | ### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` @@ -1011,11 +1024,18 @@ The member name of a group obtained from the remote resource that this private e ### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` -A private ip address obtained from the private endpoint's subnet. +A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1059,12 +1079,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1075,7 +1095,7 @@ The name of the private endpoint. ### Parameter: `privateEndpoints.privateDnsZoneGroupName` -The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. +The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. - Required: No - Type: string @@ -1178,7 +1198,7 @@ The principal type of the assigned principal ID. ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". - Required: No - Type: string @@ -1319,7 +1339,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.3.2` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Notes diff --git a/avm/res/data-factory/factory/main.bicep b/avm/res/data-factory/factory/main.bicep index 77562721b61..9f692af3d6c 100644 --- a/avm/res/data-factory/factory/main.bicep +++ b/avm/res/data-factory/factory/main.bicep @@ -226,12 +226,13 @@ resource dataFactory_roleAssignments 'Microsoft.Authorization/roleAssignments@20 scope: dataFactory }] -module dataFactory_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.2' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module dataFactory_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-dataFactory-PrivateEndpoint-${index}' params: { + name: privateEndpoint.?name ?? 'pep-${last(split(dataFactory.id, '/'))}-${privateEndpoint.?service ?? 'dataFactory'}-${index}' privateLinkServiceConnections: [ { - name: name + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(dataFactory.id, '/'))}-${privateEndpoint.?service ?? 'dataFactory'}-${index}' properties: { privateLinkServiceId: dataFactory.id groupIds: [ @@ -240,7 +241,18 @@ module dataFactory_privateEndpoints 'br/public:avm/res/network/private-endpoint: } } ] - name: privateEndpoint.?name ?? 'pep-${last(split(dataFactory.id, '/'))}-${privateEndpoint.?service ?? 'dataFactory'}-${index}' + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(dataFactory.id, '/'))}-${privateEndpoint.?service ?? 'dataFactory'}-${index}' + properties: { + privateLinkServiceId: dataFactory.id + groupIds: [ + privateEndpoint.?service ?? 'dataFactory' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock @@ -249,7 +261,6 @@ module dataFactory_privateEndpoints 'br/public:avm/res/network/private-endpoint: privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -322,24 +333,31 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string - @description('Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided.') + @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') privateDnsZoneGroupName: string? @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { - @description('Required. Fqdn that resolves to private endpoint ip address.') + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? - @description('Required. A list of private ip addresses of the private endpoint.') + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @@ -356,7 +374,7 @@ type privateEndpointType = { @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') memberName: string - @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') privateIPAddress: string } }[]? @@ -376,9 +394,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/data-factory/factory/main.json b/avm/res/data-factory/factory/main.json index ec293b4da57..3d71e6ca6c4 100644 --- a/avm/res/data-factory/factory/main.json +++ b/avm/res/data-factory/factory/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "6048154575317305583" + "templateHash": "15512301092613886840" }, "name": "Data Factories", "description": "This module deploys a Data Factory.", @@ -150,7 +150,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." } }, "subnetResourceId": { @@ -163,7 +163,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." } }, "privateDnsZoneResourceIds": { @@ -176,6 +176,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -185,7 +200,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -194,7 +209,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -233,7 +248,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -284,13 +299,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -1130,10 +1138,13 @@ }, "mode": "Incremental", "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DataFactory/factories', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'dataFactory'), copyIndex()))]" + }, "privateLinkServiceConnections": { "value": [ { - "name": "[parameters('name')]", + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DataFactory/factories', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'dataFactory'), copyIndex()))]", "properties": { "privateLinkServiceId": "[resourceId('Microsoft.DataFactory/factories', parameters('name'))]", "groupIds": [ @@ -1143,9 +1154,7 @@ } ] }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DataFactory/factories', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'dataFactory'), copyIndex()))]" - }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DataFactory/factories', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'dataFactory'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DataFactory/factories', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'dataFactory')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -1170,9 +1179,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -1193,8 +1199,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -1243,7 +1249,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -1559,7 +1565,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1664,8 +1670,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18168683629401652671" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1776,6 +1782,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep b/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep index 7cabaa0fc70..e825639f2ee 100644 --- a/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep +++ b/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep @@ -134,9 +134,15 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' - application: 'CARML' + application: 'AVM' } } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } ] roleAssignments: [ { diff --git a/avm/res/data-factory/factory/version.json b/avm/res/data-factory/factory/version.json index 83083db6945..1c035df49f2 100644 --- a/avm/res/data-factory/factory/version.json +++ b/avm/res/data-factory/factory/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] diff --git a/avm/res/desktop-virtualization/host-pool/README.md b/avm/res/desktop-virtualization/host-pool/README.md index 3c31139d596..c38e99d1eac 100644 --- a/avm/res/desktop-virtualization/host-pool/README.md +++ b/avm/res/desktop-virtualization/host-pool/README.md @@ -32,8 +32,7 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using large parameter set](#example-2-using-large-parameter-set) -- [Using Private Endpoints](#example-3-using-private-endpoints) -- [WAF-aligned](#example-4-waf-aligned) +- [WAF-aligned](#example-3-waf-aligned) ### Example 1: _Using only defaults_ @@ -148,6 +147,12 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' = ] subnetResourceId: '' } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } ] publicNetworkAccess: 'Disabled' roleAssignments: [ @@ -278,6 +283,12 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' = }, "privateEndpoints": { "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "" + }, { "privateDnsZoneResourceIds": [ "" @@ -341,77 +352,7 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

-### Example 3: _Using Private Endpoints_ - -This instance deploys the module with Private Endpoints. - - -

- -via Bicep module - -```bicep -module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' = { - name: '${uniqueString(deployment().name, resourceLocation)}-test-dvhppe' - params: { - // Required parameters - name: 'dvhppe001' - // Non-required parameters - location: '' - privateEndpoints: [ - { - privateDnsZoneResourceIds: [ - '' - ] - subnetResourceId: '' - } - ] - publicNetworkAccess: 'Disabled' - } -} -``` - -
-

- -

- -via JSON Parameter file - -```json -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - // Required parameters - "name": { - "value": "dvhppe001" - }, - // Non-required parameters - "location": { - "value": "" - }, - "privateEndpoints": { - "value": [ - { - "privateDnsZoneResourceIds": [ - "" - ], - "subnetResourceId": "" - } - ] - }, - "publicNetworkAccess": { - "value": "Disabled" - } - } -} -``` - -
-

- -### Example 4: _WAF-aligned_ +### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -836,14 +777,15 @@ Configuration details for private endpoints. | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "connection". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `privateEndpoints.subnetResourceId` @@ -959,6 +901,13 @@ A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1002,12 +951,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1121,7 +1070,7 @@ The principal type of the assigned principal ID. ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "connection". +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". - Required: No - Type: string @@ -1352,7 +1301,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm-res-network-privateendpoint:0.1.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/desktop-virtualization/host-pool/main.bicep b/avm/res/desktop-virtualization/host-pool/main.bicep index 9e4cb174728..d173f8e6f07 100644 --- a/avm/res/desktop-virtualization/host-pool/main.bicep +++ b/avm/res/desktop-virtualization/host-pool/main.bicep @@ -196,22 +196,41 @@ resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2023-09-05' = { } } -module hostPool_privateEndpoints 'br/public:avm-res-network-privateendpoint:0.1.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module hostPool_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-HostPool-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'connection' - ] name: privateEndpoint.?name ?? 'pep-${last(split(hostPool.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' - serviceResourceId: hostPool.id + privateLinkServiceConnections: [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(hostPool.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: hostPool.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + } + } + ] + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(hostPool.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: hostPool.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId - enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -335,14 +354,13 @@ type roleAssignmentType = { }[]? type privateEndpointType = { - @sys.description('Optional. The name of the private endpoint.') name: string? @sys.description('Optional. The location to deploy the private endpoint to.') location: string? - @sys.description('Optional. The service (sub-) type to deploy the private endpoint for. For example "connection".') + @sys.description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @sys.description('Required. Resource ID of the subnet where the endpoint needs to be created.') @@ -354,6 +372,13 @@ type privateEndpointType = { @sys.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[]? + @sys.description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @sys.description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @sys.description('Optional. Custom DNS configurations.') customDnsConfigs: { @sys.description('Required. Fqdn that resolves to private endpoint IP address.') @@ -396,9 +421,6 @@ type privateEndpointType = { @sys.description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @sys.description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @sys.description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/desktop-virtualization/host-pool/main.json b/avm/res/desktop-virtualization/host-pool/main.json index 6719f26b5d0..698856fcc88 100644 --- a/avm/res/desktop-virtualization/host-pool/main.json +++ b/avm/res/desktop-virtualization/host-pool/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "4511420670498379838" + "templateHash": "17476152824582806077" }, "name": "Azure Virtual Desktop Host Pool", "description": "This module deploys an Azure Virtual Desktop Host Pool", @@ -197,7 +197,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"connection\"." + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." } }, "subnetResourceId": { @@ -223,6 +223,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -331,13 +346,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -763,26 +771,35 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { - "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')]" - ] - }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name'))]" + "privateLinkServiceConnections": { + "value": [ + { + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')]" + ] + } + } + ] }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, "lock": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, "privateDnsZoneGroupName": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" }, @@ -795,9 +812,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -818,8 +832,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "13152465847704433697" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -834,7 +848,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -868,7 +882,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -916,6 +930,154 @@ } }, "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -931,12 +1093,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -952,18 +1108,11 @@ } }, "ipConfigurations": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/ipConfigurationsType", "metadata": { "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "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, @@ -994,7 +1143,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -1005,17 +1154,21 @@ } }, "customDnsConfigs": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/customDnsConfigType", "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1045,7 +1198,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1081,15 +1234,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -1119,7 +1264,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1158,8 +1303,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "1698104586574073002" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1270,6 +1415,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep b/avm/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep index 1150a73b43d..bda485891a3 100644 --- a/avm/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep +++ b/avm/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep @@ -89,6 +89,12 @@ module testDeployment '../../../main.bicep' = { ] subnetResourceId: nestedDependencies.outputs.subnetResourceId } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } ] loadBalancerType: 'BreadthFirst' location: resourceLocation @@ -153,4 +159,8 @@ module testDeployment '../../../main.bicep' = { ] } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] } diff --git a/avm/res/desktop-virtualization/host-pool/tests/e2e/private-endpoint/dependencies.bicep b/avm/res/desktop-virtualization/host-pool/tests/e2e/private-endpoint/dependencies.bicep deleted file mode 100644 index f18c0628e3f..00000000000 --- a/avm/res/desktop-virtualization/host-pool/tests/e2e/private-endpoint/dependencies.bicep +++ /dev/null @@ -1,49 +0,0 @@ -@description('Optional. The location to deploy to.') -param location string = resourceGroup().location - -@description('Required. The name of the Virtual Network to create.') -param virtualNetworkName string - -var addressPrefix = '10.0.0.0/16' - -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: 'defaultSubnet' - properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) - } - } - ] - } -} - -resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { - name: 'privatelink.wvd.microsoft.com' - location: 'global' - - resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { - name: '${virtualNetwork.name}-vnetlink' - location: 'global' - properties: { - virtualNetwork: { - id: virtualNetwork.id - } - registrationEnabled: false - } - } -} - -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id - -@description('The resource ID of the created Private DNS Zone.') -output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/desktop-virtualization/host-pool/tests/e2e/private-endpoint/main.test.bicep b/avm/res/desktop-virtualization/host-pool/tests/e2e/private-endpoint/main.test.bicep deleted file mode 100644 index 0cf73ba6a0d..00000000000 --- a/avm/res/desktop-virtualization/host-pool/tests/e2e/private-endpoint/main.test.bicep +++ /dev/null @@ -1,61 +0,0 @@ -targetScope = 'subscription' - -metadata name = 'Using Private Endpoints' -metadata description = 'This instance deploys the module with Private Endpoints.' - -@description('Optional. The name of the resource group to deploy for testing purposes.') -@maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.hostpools-${serviceShort}-rg' - -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - -@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'dvhppe' - -@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') -param namePrefix string = '#_namePrefix_#' - -// ============ // -// Dependencies // -// ============ // - -// General resources -// ================= - -resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: resourceGroupName - location: resourceLocation -} - -module nestedDependencies 'dependencies.bicep' = { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' - params: { - virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: resourceLocation - } -} - -// ============== // -// Test Execution // -// ============== // - -@batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - location: resourceLocation - publicNetworkAccess: 'Disabled' - privateEndpoints: [ - { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] - subnetResourceId: nestedDependencies.outputs.subnetResourceId - } - ] - } -}] diff --git a/avm/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep b/avm/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep index d77316a896b..91b13e6544d 100644 --- a/avm/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep @@ -67,4 +67,7 @@ module testDeployment '../../../main.bicep' = { Role: 'DeploymentValidation' } } + dependsOn: [ + diagnosticDependencies + ] } diff --git a/avm/res/desktop-virtualization/host-pool/version.json b/avm/res/desktop-virtualization/host-pool/version.json index 7245f148728..729ac87673b 100644 --- a/avm/res/desktop-virtualization/host-pool/version.json +++ b/avm/res/desktop-virtualization/host-pool/version.json @@ -1,7 +1,7 @@ { - "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", - "pathFilters": [ - "./main.json" - ] - } \ No newline at end of file + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/res/desktop-virtualization/workspace/README.md b/avm/res/desktop-virtualization/workspace/README.md index 398a16117c5..614a16878ab 100644 --- a/avm/res/desktop-virtualization/workspace/README.md +++ b/avm/res/desktop-virtualization/workspace/README.md @@ -32,8 +32,7 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using large parameter set](#example-2-using-large-parameter-set) -- [Using Private Endpoints](#example-3-using-private-endpoints) -- [WAF-aligned](#example-4-waf-aligned) +- [WAF-aligned](#example-3-waf-aligned) ### Example 1: _Using only defaults_ @@ -373,231 +372,7 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

-### Example 3: _Using Private Endpoints_ - -This instance deploys the module with Private Endpoints. - - -

- -via Bicep module - -```bicep -module workspace 'br/public:avm/res/desktop-virtualization/workspace:' = { - name: '${uniqueString(deployment().name, resourceLocation)}-test-dvwspe' - params: { - // Required parameters - name: 'dvwspe001' - // Non-required parameters - location: '' - privateEndpoints: [ - { - customDnsConfigs: [ - { - fqdn: 'abc.workspace.com' - ipAddresses: [ - '10.0.0.10' - '10.0.0.13' - ] - } - ] - ipConfigurations: [ - { - name: 'myIPconfig-feed1' - properties: { - groupId: 'feed' - memberName: 'web-r0' - privateIPAddress: '10.0.0.10' - } - } - { - name: 'myIPconfig-feed2' - properties: { - groupId: 'feed' - memberName: 'web-r1' - privateIPAddress: '10.0.0.13' - } - } - ] - privateDnsZoneResourceIds: [ - '' - ] - roleAssignments: [ - { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' - } - ] - service: 'feed' - subnetResourceId: '' - tags: { - Environment: 'Non-Prod' - 'hidden-title': 'This is visible in the resource name' - Role: 'DeploymentValidation' - } - } - { - customDnsConfigs: [ - { - fqdn: 'abc.workspace.com' - ipAddresses: [ - '10.0.0.11' - ] - } - ] - ipConfigurations: [ - { - name: 'myIPconfig-global' - properties: { - groupId: 'global' - memberName: 'web' - privateIPAddress: '10.0.0.11' - } - } - ] - privateDnsZoneResourceIds: [ - '' - ] - roleAssignments: [ - { - principalId: '' - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Reader' - } - ] - service: 'global' - subnetResourceId: '' - tags: { - Environment: 'Non-Prod' - 'hidden-title': 'This is visible in the resource name' - Role: 'DeploymentValidation' - } - } - ] - publicNetworkAccess: 'Disabled' - } -} -``` - -
-

- -

- -via JSON Parameter file - -```json -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - // Required parameters - "name": { - "value": "dvwspe001" - }, - // Non-required parameters - "location": { - "value": "" - }, - "privateEndpoints": { - "value": [ - { - "customDnsConfigs": [ - { - "fqdn": "abc.workspace.com", - "ipAddresses": [ - "10.0.0.10", - "10.0.0.13" - ] - } - ], - "ipConfigurations": [ - { - "name": "myIPconfig-feed1", - "properties": { - "groupId": "feed", - "memberName": "web-r0", - "privateIPAddress": "10.0.0.10" - } - }, - { - "name": "myIPconfig-feed2", - "properties": { - "groupId": "feed", - "memberName": "web-r1", - "privateIPAddress": "10.0.0.13" - } - } - ], - "privateDnsZoneResourceIds": [ - "" - ], - "roleAssignments": [ - { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" - } - ], - "service": "feed", - "subnetResourceId": "", - "tags": { - "Environment": "Non-Prod", - "hidden-title": "This is visible in the resource name", - "Role": "DeploymentValidation" - } - }, - { - "customDnsConfigs": [ - { - "fqdn": "abc.workspace.com", - "ipAddresses": [ - "10.0.0.11" - ] - } - ], - "ipConfigurations": [ - { - "name": "myIPconfig-global", - "properties": { - "groupId": "global", - "memberName": "web", - "privateIPAddress": "10.0.0.11" - } - } - ], - "privateDnsZoneResourceIds": [ - "" - ], - "roleAssignments": [ - { - "principalId": "", - "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Reader" - } - ], - "service": "global", - "subnetResourceId": "", - "tags": { - "Environment": "Non-Prod", - "hidden-title": "This is visible in the resource name", - "Role": "DeploymentValidation" - } - } - ] - }, - "publicNetworkAccess": { - "value": "Disabled" - } - } -} -``` - -
-

- -### Example 4: _WAF-aligned_ +### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -910,9 +685,10 @@ Configuration details for private endpoints. | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | @@ -1039,6 +815,13 @@ A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1082,12 +865,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1326,7 +1109,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm-res-network-privateendpoint:0.1.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/desktop-virtualization/workspace/main.bicep b/avm/res/desktop-virtualization/workspace/main.bicep index 76b833e5559..b696e0baca5 100644 --- a/avm/res/desktop-virtualization/workspace/main.bicep +++ b/avm/res/desktop-virtualization/workspace/main.bicep @@ -90,22 +90,41 @@ resource workspace 'Microsoft.DesktopVirtualization/workspaces@2022-10-14-previe } } -module workspace_privateEndpoints 'br/public:avm-res-network-privateendpoint:0.1.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module workspace_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-Workspace-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.service + name: privateEndpoint.?name ?? 'pep-${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + privateLinkServiceConnections: [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: workspace.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + } + } ] - name: privateEndpoint.?name ?? 'pep-${last(split(workspace.id, '/'))}-${privateEndpoint.?service}-${index}' - serviceResourceId: workspace.id + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: workspace.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId - enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -227,7 +246,6 @@ type roleAssignmentType = { }[]? type privateEndpointType = { - @sys.description('Optional. The name of the private endpoint.') name: string? @@ -246,6 +264,13 @@ type privateEndpointType = { @sys.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[]? + @sys.description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @sys.description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @sys.description('Optional. Custom DNS configurations.') customDnsConfigs: { @sys.description('Required. Fqdn that resolves to private endpoint IP address.') @@ -288,9 +313,6 @@ type privateEndpointType = { @sys.description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @sys.description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @sys.description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/desktop-virtualization/workspace/main.json b/avm/res/desktop-virtualization/workspace/main.json index ac075c7a41d..504dc0dc060 100644 --- a/avm/res/desktop-virtualization/workspace/main.json +++ b/avm/res/desktop-virtualization/workspace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "4530090726614666900" + "templateHash": "1061929067377896447" }, "name": "Workspace", "description": "This module deploys an Azure Virtual Desktop Workspace.", @@ -215,6 +215,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -323,13 +338,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -577,26 +585,35 @@ }, "mode": "Incremental", "parameters": { - "groupIds": { - "value": [ - "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service]" - ] - }, "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name'))]" + "privateLinkServiceConnections": { + "value": [ + { + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')]" + ] + } + } + ] }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, "lock": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, "privateDnsZoneGroupName": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" }, @@ -609,9 +626,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -632,8 +646,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "13152465847704433697" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -648,7 +662,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -682,7 +696,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -730,6 +744,154 @@ } }, "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -745,12 +907,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -766,18 +922,11 @@ } }, "ipConfigurations": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/ipConfigurationsType", "metadata": { "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "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, @@ -808,7 +957,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -819,17 +968,21 @@ } }, "customDnsConfigs": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/customDnsConfigType", "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -859,7 +1012,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -895,15 +1048,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -933,7 +1078,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -972,8 +1117,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "1698104586574073002" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1084,6 +1229,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep b/avm/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep index 5cb9db486c2..e81a1febd03 100644 --- a/avm/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep @@ -178,4 +178,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: 'myCustomLockName' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/desktop-virtualization/workspace/tests/e2e/private-endpoint/dependencies.bicep b/avm/res/desktop-virtualization/workspace/tests/e2e/private-endpoint/dependencies.bicep deleted file mode 100644 index 2e1877ac5da..00000000000 --- a/avm/res/desktop-virtualization/workspace/tests/e2e/private-endpoint/dependencies.bicep +++ /dev/null @@ -1,59 +0,0 @@ -@description('Optional. The location to deploy to.') -param location string = resourceGroup().location - -@description('Required. The name of the Virtual Network to create.') -param virtualNetworkName string - -@description('Required. The name of the Managed Identity to create.') -param managedIdentityName string - -var addressPrefix = '10.0.0.0/16' - -resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { - name: managedIdentityName - location: location -} - -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: 'defaultSubnet' - properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) - } - } - ] - } -} - -resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { - name: 'privatelink.wvd.microsoft.com' - location: 'global' - resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { - name: '${virtualNetwork.name}-vnetlink' - location: 'global' - properties: { - virtualNetwork: { - id: virtualNetwork.id - } - registrationEnabled: false - } - } -} - -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id - -@description('The resource ID of the created Private DNS Zone.') -output privateDNSZoneResourceId string = privateDNSZone.id - -@description('The principal ID of the created Managed Identity.') -output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/desktop-virtualization/workspace/tests/e2e/private-endpoint/main.test.bicep b/avm/res/desktop-virtualization/workspace/tests/e2e/private-endpoint/main.test.bicep deleted file mode 100644 index 2bef56353da..00000000000 --- a/avm/res/desktop-virtualization/workspace/tests/e2e/private-endpoint/main.test.bicep +++ /dev/null @@ -1,139 +0,0 @@ -targetScope = 'subscription' - -metadata name = 'Using Private Endpoints' -metadata description = 'This instance deploys the module with Private Endpoints.' - -@description('Optional. The name of the resource group to deploy for testing purposes.') -@maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.workspace-${serviceShort}-rg' - -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - -@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'dvwspe' - -@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') -param namePrefix string = '#_namePrefix_#' - -// ============ // -// Dependencies // -// ============ // - -// General resources -// ================= - -resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: resourceGroupName - location: resourceLocation -} - -module nestedDependencies 'dependencies.bicep' = { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' - params: { - virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: resourceLocation - managedIdentityName: 'dvwspe-managedidentity' - } -} - -// ============== // -// Test Execution // -// ============== // - -@batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - location: resourceLocation - publicNetworkAccess: 'Disabled' - privateEndpoints: [ - { - service: 'feed' - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] - subnetResourceId: nestedDependencies.outputs.subnetResourceId - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' - } - roleAssignments: [ - { - roleDefinitionIdOrName: 'Reader' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - ] - ipConfigurations: [ - { - name: 'myIPconfig-feed1' - properties: { - groupId: 'feed' - memberName: 'web-r0' - privateIPAddress: '10.0.0.10' - } - } - { - name: 'myIPconfig-feed2' - properties: { - groupId: 'feed' - memberName: 'web-r1' - privateIPAddress: '10.0.0.13' - } - } - ] - customDnsConfigs: [ - { - fqdn: 'abc.workspace.com' - ipAddresses: [ - '10.0.0.10' - '10.0.0.13' - ] - } - ] - } - { - service: 'global' - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] - subnetResourceId: nestedDependencies.outputs.subnetResourceId - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' - } - roleAssignments: [ - { - roleDefinitionIdOrName: 'Reader' - principalId: nestedDependencies.outputs.managedIdentityPrincipalId - principalType: 'ServicePrincipal' - } - ] - ipConfigurations: [ - { - name: 'myIPconfig-global' - properties: { - groupId: 'global' - memberName: 'web' - privateIPAddress: '10.0.0.11' - } - } - ] - customDnsConfigs: [ - { - fqdn: 'abc.workspace.com' - ipAddresses: [ - '10.0.0.11' - ] - } - ] - } - ] - } -}] diff --git a/avm/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep index 6650e01b105..1103178216d 100644 --- a/avm/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -68,4 +68,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + diagnosticDependencies + ] }] diff --git a/avm/res/desktop-virtualization/workspace/version.json b/avm/res/desktop-virtualization/workspace/version.json index 7245f148728..76049e1c4ad 100644 --- a/avm/res/desktop-virtualization/workspace/version.json +++ b/avm/res/desktop-virtualization/workspace/version.json @@ -1,7 +1,7 @@ { - "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", - "pathFilters": [ - "./main.json" - ] - } \ No newline at end of file + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md index beb99218f9a..5202d4df234 100644 --- a/avm/res/document-db/database-account/README.md +++ b/avm/res/document-db/database-account/README.md @@ -1132,6 +1132,13 @@ module databaseAccount 'br/public:avm/res/document-db/database-account: Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'Sql' + subnetResourceId: '' + } ] roleAssignments: [ { @@ -1303,6 +1310,13 @@ module databaseAccount 'br/public:avm/res/document-db/database-account: "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "service": "Sql", + "subnetResourceId": "" } ] }, @@ -1452,6 +1466,20 @@ module databaseAccount 'br/public:avm/res/document-db/database-account: } ] location: '' + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'Sql' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] sqlDatabases: [ { containers: [ @@ -1542,6 +1570,22 @@ module databaseAccount 'br/public:avm/res/document-db/database-account: "location": { "value": "" }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "service": "Sql", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, "sqlDatabases": { "value": [ { @@ -2046,7 +2090,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | Parameter | Type | Description | | :-- | :-- | :-- | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". | | [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | **Optional parameters** @@ -2058,9 +2102,10 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | @@ -2069,7 +2114,7 @@ Configuration details for private endpoints. For security reasons, it is recomme ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". - Required: Yes - Type: string @@ -2187,6 +2232,13 @@ A private ip address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -2230,12 +2282,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -2492,7 +2544,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/document-db/database-account/main.bicep b/avm/res/document-db/database-account/main.bicep index e472d947fcf..7adb1ac9978 100644 --- a/avm/res/document-db/database-account/main.bicep +++ b/avm/res/document-db/database-account/main.bicep @@ -317,21 +317,33 @@ module databaseAccount_gremlinDatabases 'gremlin-database/main.bicep' = [for gre } }] -module databaseAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { +module databaseAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-databaseAccount-PrivateEndpoint-${index}' params: { - privateLinkServiceConnections: [ + name: privateEndpoint.?name ?? 'pep-${last(split(databaseAccount.id, '/'))}-${privateEndpoint.service}-${index}' + privateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections != true ? [ { - name: name + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(databaseAccount.id, '/'))}-${privateEndpoint.service}-${index}' properties: { privateLinkServiceId: databaseAccount.id groupIds: [ - privateEndpoint.?service ?? 'Sql' + privateEndpoint.service ] } } - ] - name: privateEndpoint.?name ?? 'pep-${last(split(databaseAccount.id, '/'))}-${privateEndpoint.?service ?? 'vault'}-${index}' + ] : null + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(databaseAccount.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: databaseAccount.id + groupIds: [ + privateEndpoint.service + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location @@ -340,7 +352,6 @@ module databaseAccount_privateEndpoints 'br/public:avm/res/network/private-endpo privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds @@ -413,7 +424,7 @@ 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".') + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') service: string @description('Required. Resource ID of the subnet where the endpoint needs to be created.') @@ -425,6 +436,13 @@ type privateEndpointType = { @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { @description('Required. Fqdn that resolves to private endpoint ip address.') @@ -467,9 +485,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/document-db/database-account/main.json b/avm/res/document-db/database-account/main.json index 454bcda8db1..3a3f8d75a59 100644 --- a/avm/res/document-db/database-account/main.json +++ b/avm/res/document-db/database-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "14608365683973460476" + "templateHash": "6178968809986230954" }, "name": "DocumentDB Database Accounts", "description": "This module deploys a DocumentDB Database Account.", @@ -149,7 +149,7 @@ "service": { "type": "string", "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\"." } }, "subnetResourceId": { @@ -175,6 +175,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -283,13 +298,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -1715,22 +1723,11 @@ }, "mode": "Incremental", "parameters": { - "privateLinkServiceConnections": { - "value": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]", - "groupIds": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'Sql')]" - ] - } - } - ] - }, "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -1755,9 +1752,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -1778,8 +1772,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -1828,7 +1822,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -1906,7 +1900,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -2009,7 +2003,7 @@ "fqdn": { "type": "string", "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -2018,7 +2012,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -2144,7 +2138,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2249,8 +2243,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "18168683629401652671" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -2361,6 +2355,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep index ad94f420669..9931f2cbd2a 100644 --- a/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/gremlindb/main.test.bicep @@ -170,4 +170,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep index 48b812836a3..463ff7708ee 100644 --- a/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/mongodb/main.test.bicep @@ -304,4 +304,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep index 15f0bddb534..c67998598b0 100644 --- a/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/plain/main.test.bicep @@ -119,4 +119,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/document-db/database-account/tests/e2e/sqldb/dependencies.bicep b/avm/res/document-db/database-account/tests/e2e/sqldb/dependencies.bicep index 9068571d83d..cd88a1370a1 100644 --- a/avm/res/document-db/database-account/tests/e2e/sqldb/dependencies.bicep +++ b/avm/res/document-db/database-account/tests/e2e/sqldb/dependencies.bicep @@ -30,7 +30,19 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { { name: 'defaultSubnet' properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + } + } + { + name: 'custom-private-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + } + } + { + name: 'custom-private-subnet-2' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 2) } } ] @@ -92,8 +104,14 @@ output managedIdentityPrincipalId string = managedIdentity.properties.principalI @description('The resource ID of the created Managed Identity.') output managedIdentityResourceId string = managedIdentity.id -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id +@description('The resource ID of the created Virtual Network Default Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the 2nd created Virtual Network Subnet.') +output customSubnet1ResourceId string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the 3rd created Virtual Network Subnet.') +output customSubnet2ResourceId string = virtualNetwork.properties.subnets[2].id @description('The resource ID of the created Private DNS Zone.') output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep index 70a0d824696..4a839dd38ff 100644 --- a/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/sqldb/main.test.bicep @@ -98,13 +98,20 @@ module testDeployment '../../../main.bicep' = { nestedDependencies.outputs.privateDNSZoneResourceId ] service: 'Sql' - subnetResourceId: nestedDependencies.outputs.subnetResourceId + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + service: 'Sql' + subnetResourceId: nestedDependencies.outputs.customSubnet2ResourceId + } ] roleAssignments: [ { @@ -208,4 +215,8 @@ module testDeployment '../../../main.bicep' = { Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] } diff --git a/avm/res/document-db/database-account/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/document-db/database-account/tests/e2e/waf-aligned/dependencies.bicep index d9e107c4ea0..e42185366b5 100644 --- a/avm/res/document-db/database-account/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/document-db/database-account/tests/e2e/waf-aligned/dependencies.bicep @@ -4,9 +4,50 @@ param location string = resourceGroup().location @description('Required. The name of the Managed Identity to create.') param managedIdentityName string +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + @description('Required. The name of the Deployment Script to create to get the paired region name.') param pairedRegionScriptName string +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.documents.azure.com' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { name: managedIdentityName location: location @@ -44,3 +85,9 @@ resource getPairedRegionScript 'Microsoft.Resources/deploymentScripts@2020-10-01 @description('The name of the paired region.') output pairedRegionName string = getPairedRegionScript.properties.outputs.pairedRegionName + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep index 4f9c11197e1..7829519f3dc 100644 --- a/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/document-db/database-account/tests/e2e/waf-aligned/main.test.bicep @@ -38,6 +38,7 @@ module nestedDependencies 'dependencies.bicep' = { name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' params: { managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' pairedRegionScriptName: 'dep-${namePrefix}-ds-${serviceShort}' location: resourceLocation } @@ -87,6 +88,20 @@ module testDeployment '../../../main.bicep' = { } ] location: resourceLocation + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + service: 'Sql' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] sqlDatabases: [ { containers: [ @@ -130,4 +145,8 @@ module testDeployment '../../../main.bicep' = { Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] } diff --git a/avm/res/document-db/database-account/version.json b/avm/res/document-db/database-account/version.json index 83083db6945..c177b1bb58b 100644 --- a/avm/res/document-db/database-account/version.json +++ b/avm/res/document-db/database-account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.3", "pathFilters": [ "./main.json" ] diff --git a/avm/res/event-grid/domain/README.md b/avm/res/event-grid/domain/README.md index 10afb3de293..229f56e4442 100644 --- a/avm/res/event-grid/domain/README.md +++ b/avm/res/event-grid/domain/README.md @@ -33,8 +33,7 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using large parameter set](#example-2-using-large-parameter-set) -- [Using private endpoint](#example-3-using-private-endpoint) -- [WAF-aligned](#example-4-waf-aligned) +- [WAF-aligned](#example-3-waf-aligned) ### Example 1: _Using only defaults_ @@ -130,7 +129,6 @@ module domain 'br/public:avm/res/event-grid/domain:' = { privateDnsZoneResourceIds: [ '' ] - service: 'domain' subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -138,6 +136,12 @@ module domain 'br/public:avm/res/event-grid/domain:' = { Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } ] roleAssignments: [ { @@ -224,13 +228,18 @@ module domain 'br/public:avm/res/event-grid/domain:' = { "privateDnsZoneResourceIds": [ "" ], - "service": "domain", "subnetResourceId": "", "tags": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "" } ] }, @@ -272,95 +281,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

-### Example 3: _Using private endpoint_ - -This instance deploys the module with private endpoint. - - -

- -via Bicep module - -```bicep -module domain 'br/public:avm/res/event-grid/domain:' = { - name: '${uniqueString(deployment().name, resourceLocation)}-test-egdpe' - params: { - // Required parameters - name: 'egdpe001' - // Non-required parameters - location: '' - privateEndpoints: [ - { - privateDnsZoneResourceIds: [ - '' - ] - subnetResourceId: '' - tags: { - Environment: 'Non-Prod' - 'hidden-title': 'This is visible in the resource name' - Role: 'DeploymentValidation' - } - } - ] - tags: { - Environment: 'Non-Prod' - 'hidden-title': 'This is visible in the resource name' - Role: 'DeploymentValidation' - } - } -} -``` - -
-

- -

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

- -### Example 4: _WAF-aligned_ +### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -817,14 +738,15 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | -| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `privateEndpoints.subnetResourceId` @@ -852,19 +774,19 @@ Custom DNS configurations. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint ip address. | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private ip addresses of the private endpoint. | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` -Fqdn that resolves to private endpoint ip address. +Fqdn that resolves to private endpoint IP address. - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` -A list of private ip addresses of the private endpoint. +A list of private IP addresses of the private endpoint. - Required: Yes - Type: array @@ -917,7 +839,7 @@ Properties of private endpoint IP configurations. | :-- | :-- | :-- | | [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | | [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | -| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private ip address obtained from the private endpoint's subnet. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | ### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` @@ -935,11 +857,18 @@ The member name of a group obtained from the remote resource that this private e ### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` -A private ip address obtained from the private endpoint's subnet. +A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -983,12 +912,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -999,7 +928,7 @@ The name of the private endpoint. ### Parameter: `privateEndpoints.privateDnsZoneGroupName` -The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. +The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. - Required: No - Type: string @@ -1102,7 +1031,7 @@ The principal type of the assigned principal ID. ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". - Required: No - Type: string @@ -1250,7 +1179,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm-res-network-privateendpoint:0.1.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/event-grid/domain/main.bicep b/avm/res/event-grid/domain/main.bicep index 7cf3d9fa9eb..2b02292287e 100644 --- a/avm/res/event-grid/domain/main.bicep +++ b/avm/res/event-grid/domain/main.bicep @@ -143,27 +143,45 @@ resource domain_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-0 scope: domain }] -module domain_privateEndpoints 'br/public:avm-res-network-privateendpoint:0.1.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { - name: '${uniqueString(deployment().name, location)}-domain-PrivateEndpoint-${index}' +module domain_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-Domain-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'domain' - ] name: privateEndpoint.?name ?? 'pep-${last(split(domain.id, '/'))}-${privateEndpoint.?service ?? 'domain'}-${index}' - serviceResourceId: domain.id + privateLinkServiceConnections: [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(domain.id, '/'))}-${privateEndpoint.?service ?? 'domain'}-${index}' + properties: { + privateLinkServiceId: domain.id + groupIds: [ + privateEndpoint.?service ?? 'domain' + ] + } + } + ] + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(domain.id, '/'))}-${privateEndpoint.?service ?? 'domain'}-${index}' + properties: { + privateLinkServiceId: domain.id + groupIds: [ + privateEndpoint.?service ?? 'domain' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName - enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry } }] @@ -246,24 +264,31 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string - @description('Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided.') + @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') privateDnsZoneGroupName: string? @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { - @description('Required. Fqdn that resolves to private endpoint ip address.') + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? - @description('Required. A list of private ip addresses of the private endpoint.') + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @@ -280,7 +305,7 @@ type privateEndpointType = { @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') memberName: string - @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') privateIPAddress: string } }[]? @@ -300,9 +325,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/event-grid/domain/main.json b/avm/res/event-grid/domain/main.json index 6c5b06c183a..287a5989c63 100644 --- a/avm/res/event-grid/domain/main.json +++ b/avm/res/event-grid/domain/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "13095982235255644248" + "templateHash": "7406933903897002331" }, "name": "Event Grid Domains", "description": "This module deploys an Event Grid Domain.", @@ -150,7 +150,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." } }, "subnetResourceId": { @@ -163,7 +163,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." } }, "privateDnsZoneResourceIds": { @@ -176,6 +176,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -185,7 +200,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -194,7 +209,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -233,7 +248,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -284,13 +299,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -748,24 +756,30 @@ }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-domain-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-Domain-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "groupIds": { - "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'domain')]" - ] - }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.EventGrid/domains', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'domain'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.EventGrid/domains', parameters('name'))]" + "privateLinkServiceConnections": { + "value": [ + { + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.EventGrid/domains', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'domain'), copyIndex()))]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.EventGrid/domains', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'domain')]" + ] + } + } + ] }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.EventGrid/domains', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'domain'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.EventGrid/domains', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'domain')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -775,6 +789,9 @@ "lock": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, "privateDnsZoneGroupName": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" }, @@ -787,9 +804,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -801,9 +815,6 @@ }, "customNetworkInterfaceName": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" } }, "template": { @@ -813,8 +824,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "13152465847704433697" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -829,7 +840,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -863,7 +874,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -911,6 +922,154 @@ } }, "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -926,12 +1085,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -947,18 +1100,11 @@ } }, "ipConfigurations": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/ipConfigurationsType", "metadata": { "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "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, @@ -989,7 +1135,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -1000,17 +1146,21 @@ } }, "customDnsConfigs": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/customDnsConfigType", "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1040,7 +1190,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1076,15 +1226,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -1114,7 +1256,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1153,8 +1295,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "1698104586574073002" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1265,6 +1407,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep b/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep index 2f2e04933a2..8e80b695fd2 100644 --- a/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep +++ b/avm/res/event-grid/domain/tests/e2e/max/main.test.bicep @@ -95,7 +95,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId ] - service: 'domain' subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' @@ -103,6 +102,12 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } ] roleAssignments: [ { @@ -130,4 +135,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' '${namePrefix}-topic-${serviceShort}001' ] } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/event-grid/domain/tests/e2e/pe/dependencies.bicep b/avm/res/event-grid/domain/tests/e2e/pe/dependencies.bicep deleted file mode 100644 index 4d31fc9282e..00000000000 --- a/avm/res/event-grid/domain/tests/e2e/pe/dependencies.bicep +++ /dev/null @@ -1,49 +0,0 @@ -@description('Optional. The location to deploy to.') -param location string = resourceGroup().location - -@description('Required. The name of the Virtual Network to create.') -param virtualNetworkName string - -var addressPrefix = '10.0.0.0/16' - -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: 'defaultSubnet' - properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) - } - } - ] - } -} - -resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { - name: 'privatelink.eventgrid.azure.net' - location: 'global' - - resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { - name: '${virtualNetwork.name}-vnetlink' - location: 'global' - properties: { - virtualNetwork: { - id: virtualNetwork.id - } - registrationEnabled: false - } - } -} - -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id - -@description('The resource ID of the created Private DNS Zone.') -output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/event-grid/domain/tests/e2e/pe/main.test.bicep b/avm/res/event-grid/domain/tests/e2e/pe/main.test.bicep deleted file mode 100644 index 49b2014da2d..00000000000 --- a/avm/res/event-grid/domain/tests/e2e/pe/main.test.bicep +++ /dev/null @@ -1,73 +0,0 @@ -targetScope = 'subscription' - -metadata name = 'Using private endpoint' -metadata description = 'This instance deploys the module with private endpoint.' - -// ========== // -// Parameters // -// ========== // - -@description('Optional. The name of the resource group to deploy for testing purposes.') -@maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-eventgrid.domains-${serviceShort}-rg' - -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - -@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'egdpe' - -@description('Optional. A token to inject into the name of each resource.') -param namePrefix string = '#_namePrefix_#' - -// ============ // -// Dependencies // -// ============ // - -// General resources -// ================= -resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: resourceGroupName - location: resourceLocation -} - -module nestedDependencies 'dependencies.bicep' = { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' - params: { - virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: resourceLocation - } -} - -// ============== // -// Test Execution // -// ============== // - -@batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - location: resourceLocation - privateEndpoints: [ - { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] - subnetResourceId: nestedDependencies.outputs.subnetResourceId - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' - } - } - ] - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' - } - } -}] diff --git a/avm/res/event-grid/domain/tests/e2e/waf-aligned/main.test.bicep b/avm/res/event-grid/domain/tests/e2e/waf-aligned/main.test.bicep index eaea4d3716a..17923ede99a 100644 --- a/avm/res/event-grid/domain/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/event-grid/domain/tests/e2e/waf-aligned/main.test.bicep @@ -107,4 +107,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' '${namePrefix}-topic-${serviceShort}001' ] } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/event-grid/domain/version.json b/avm/res/event-grid/domain/version.json index 8def869edeb..729ac87673b 100644 --- a/avm/res/event-grid/domain/version.json +++ b/avm/res/event-grid/domain/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] -} +} \ No newline at end of file diff --git a/avm/res/event-grid/topic/README.md b/avm/res/event-grid/topic/README.md index 8ec06042002..a8e91be4955 100644 --- a/avm/res/event-grid/topic/README.md +++ b/avm/res/event-grid/topic/README.md @@ -33,8 +33,7 @@ The following section provides usage examples for the module, which were used to - [Using only defaults](#example-1-using-only-defaults) - [Using large parameter set](#example-2-using-large-parameter-set) -- [Using private endpoint](#example-3-using-private-endpoint) -- [WAF-aligned](#example-4-waf-aligned) +- [WAF-aligned](#example-3-waf-aligned) ### Example 1: _Using only defaults_ @@ -165,7 +164,6 @@ module topic 'br/public:avm/res/event-grid/topic:' = { roleDefinitionIdOrName: '' } ] - service: 'topic' subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -173,6 +171,12 @@ module topic 'br/public:avm/res/event-grid/topic:' = { Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } ] roleAssignments: [ { @@ -293,13 +297,18 @@ module topic 'br/public:avm/res/event-grid/topic:' = { "roleDefinitionIdOrName": "" } ], - "service": "topic", "subnetResourceId": "", "tags": { "Environment": "Non-Prod", "hidden-title": "This is visible in the resource name", "Role": "DeploymentValidation" } + }, + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "" } ] }, @@ -336,95 +345,7 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

-### Example 3: _Using private endpoint_ - -This instance deploys the module with the private endpoint. - - -

- -via Bicep module - -```bicep -module topic 'br/public:avm/res/event-grid/topic:' = { - name: '${uniqueString(deployment().name, resourceLocation)}-test-egtpe' - params: { - // Required parameters - name: 'egtpe001' - // Non-required parameters - location: '' - privateEndpoints: [ - { - privateDnsZoneResourceIds: [ - '' - ] - subnetResourceId: '' - tags: { - Environment: 'Non-Prod' - 'hidden-title': 'This is visible in the resource name' - Role: 'DeploymentValidation' - } - } - ] - tags: { - Environment: 'Non-Prod' - 'hidden-title': 'This is visible in the resource name' - Role: 'DeploymentValidation' - } - } -} -``` - -
-

- -

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

- -### Example 4: _WAF-aligned_ +### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -911,14 +832,15 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | | [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | | [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | -| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | -| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | -| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | ### Parameter: `privateEndpoints.subnetResourceId` @@ -946,19 +868,19 @@ Custom DNS configurations. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint ip address. | -| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private ip addresses of the private endpoint. | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint IP address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | ### Parameter: `privateEndpoints.customDnsConfigs.fqdn` -Fqdn that resolves to private endpoint ip address. +Fqdn that resolves to private endpoint IP address. - Required: No - Type: string ### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` -A list of private ip addresses of the private endpoint. +A list of private IP addresses of the private endpoint. - Required: Yes - Type: array @@ -1011,7 +933,7 @@ Properties of private endpoint IP configurations. | :-- | :-- | :-- | | [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | | [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | -| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private ip address obtained from the private endpoint's subnet. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | ### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` @@ -1029,11 +951,18 @@ The member name of a group obtained from the remote resource that this private e ### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` -A private ip address obtained from the private endpoint's subnet. +A private IP address obtained from the private endpoint's subnet. - Required: Yes - Type: string +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + ### Parameter: `privateEndpoints.location` The location to deploy the private endpoint to. @@ -1077,12 +1006,12 @@ Specify the name of lock. - Required: No - Type: string -### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` +### Parameter: `privateEndpoints.manualConnectionRequestMessage` -Manual PrivateLink Service Connections. +A message passed to the owner of the remote resource with the manual connection request. - Required: No -- Type: array +- Type: string ### Parameter: `privateEndpoints.name` @@ -1093,7 +1022,7 @@ The name of the private endpoint. ### Parameter: `privateEndpoints.privateDnsZoneGroupName` -The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. +The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. - Required: No - Type: string @@ -1196,7 +1125,7 @@ The principal type of the assigned principal ID. ### Parameter: `privateEndpoints.service` -The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". - Required: No - Type: string @@ -1337,7 +1266,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm-res-network-privateendpoint:0.1.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.4.0` | Remote reference | ## Data Collection diff --git a/avm/res/event-grid/topic/main.bicep b/avm/res/event-grid/topic/main.bicep index f6ce5a84bfc..be240027583 100644 --- a/avm/res/event-grid/topic/main.bicep +++ b/avm/res/event-grid/topic/main.bicep @@ -145,27 +145,45 @@ resource topic_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05 scope: topic }] -module topic_privateEndpoints 'br/public:avm-res-network-privateendpoint:0.1.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { - name: '${uniqueString(deployment().name, location)}-topic-PrivateEndpoint-${index}' +module topic_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.4.0' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-Topic-PrivateEndpoint-${index}' params: { - groupIds: [ - privateEndpoint.?service ?? 'topic' - ] name: privateEndpoint.?name ?? 'pep-${last(split(topic.id, '/'))}-${privateEndpoint.?service ?? 'topic'}-${index}' - serviceResourceId: topic.id + privateLinkServiceConnections: [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(topic.id, '/'))}-${privateEndpoint.?service ?? 'topic'}-${index}' + properties: { + privateLinkServiceId: topic.id + groupIds: [ + privateEndpoint.?service ?? 'topic' + ] + } + } + ] + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections == true ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(topic.id, '/'))}-${privateEndpoint.?service ?? 'topic'}-${index}' + properties: { + privateLinkServiceId: topic.id + groupIds: [ + privateEndpoint.?service ?? 'topic' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] : null subnetResourceId: privateEndpoint.subnetResourceId location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags - manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections customDnsConfigs: privateEndpoint.?customDnsConfigs ipConfigurations: privateEndpoint.?ipConfigurations applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName - enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry } }] @@ -248,24 +266,31 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? - @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string - @description('Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided.') + @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') privateDnsZoneGroupName: string? @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') privateDnsZoneResourceIds: string[]? + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + @description('Optional. Custom DNS configurations.') customDnsConfigs: { - @description('Required. Fqdn that resolves to private endpoint ip address.') + @description('Required. Fqdn that resolves to private endpoint IP address.') fqdn: string? - @description('Required. A list of private ip addresses of the private endpoint.') + @description('Required. A list of private IP addresses of the private endpoint.') ipAddresses: string[] }[]? @@ -282,7 +307,7 @@ type privateEndpointType = { @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') memberName: string - @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') privateIPAddress: string } }[]? @@ -302,9 +327,6 @@ type privateEndpointType = { @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') tags: object? - @description('Optional. Manual PrivateLink Service Connections.') - manualPrivateLinkServiceConnections: array? - @description('Optional. Enable/Disable usage telemetry for module.') enableTelemetry: bool? }[]? diff --git a/avm/res/event-grid/topic/main.json b/avm/res/event-grid/topic/main.json index c3ef671cd37..bd6faed6088 100644 --- a/avm/res/event-grid/topic/main.json +++ b/avm/res/event-grid/topic/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "11641318899572418269" + "templateHash": "17945416734412715410" }, "name": "Event Grid Topics", "description": "This module deploys an Event Grid Topic.", @@ -150,7 +150,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." } }, "subnetResourceId": { @@ -163,7 +163,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." } }, "privateDnsZoneResourceIds": { @@ -176,6 +176,21 @@ "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, "customDnsConfigs": { "type": "array", "items": { @@ -185,7 +200,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, "ipAddresses": { @@ -194,7 +209,7 @@ "type": "string" }, "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "description": "Required. A list of private IP addresses of the private endpoint." } } } @@ -233,7 +248,7 @@ "privateIPAddress": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, @@ -284,13 +299,6 @@ "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, "enableTelemetry": { "type": "bool", "nullable": true, @@ -829,24 +837,30 @@ }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-topic-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-Topic-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "groupIds": { - "value": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic')]" - ] - }, "name": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.EventGrid/topics', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic'), copyIndex()))]" }, - "serviceResourceId": { - "value": "[resourceId('Microsoft.EventGrid/topics', parameters('name'))]" + "privateLinkServiceConnections": { + "value": [ + { + "name": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.EventGrid/topics', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic'), copyIndex()))]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.EventGrid/topics', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic')]" + ] + } + } + ] }, + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.EventGrid/topics', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.EventGrid/topics', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'topic')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", "subnetResourceId": { "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, @@ -856,6 +870,9 @@ "lock": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, "privateDnsZoneGroupName": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" }, @@ -868,9 +885,6 @@ "tags": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" - }, "customDnsConfigs": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, @@ -882,9 +896,6 @@ }, "customNetworkInterfaceName": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" } }, "template": { @@ -894,8 +905,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "13152465847704433697" + "version": "0.24.24.22086", + "templateHash": "2592884001616184297" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", @@ -910,7 +921,7 @@ "roleDefinitionIdOrName": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, "principalId": { @@ -944,7 +955,7 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." } }, "conditionVersion": { @@ -992,6 +1003,154 @@ } }, "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -1007,12 +1166,6 @@ "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, @@ -1028,18 +1181,11 @@ } }, "ipConfigurations": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/ipConfigurationsType", "metadata": { "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "groupIds": { - "type": "array", - "metadata": { - "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, @@ -1070,7 +1216,7 @@ "roleAssignments": { "$ref": "#/definitions/roleAssignmentType", "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'." + "description": "Optional. Array of role assignments to create." } }, "tags": { @@ -1081,17 +1227,21 @@ } }, "customDnsConfigs": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/customDnsConfigType", "metadata": { "description": "Optional. Custom DNS configurations." } }, "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, "enableTelemetry": { @@ -1121,7 +1271,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1157,15 +1307,7 @@ "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", "subnet": { "id": "[parameters('subnetResourceId')]" } @@ -1195,7 +1337,7 @@ "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", @@ -1234,8 +1376,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "1698104586574073002" + "version": "0.24.24.22086", + "templateHash": "9321937464667207030" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", @@ -1346,6 +1488,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } diff --git a/avm/res/event-grid/topic/tests/e2e/max/main.test.bicep b/avm/res/event-grid/topic/tests/e2e/max/main.test.bicep index ddd5fb048b8..755f0a47934 100644 --- a/avm/res/event-grid/topic/tests/e2e/max/main.test.bicep +++ b/avm/res/event-grid/topic/tests/e2e/max/main.test.bicep @@ -118,7 +118,6 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId ] - service: 'topic' subnetResourceId: nestedDependencies.outputs.subnetResourceId roleAssignments: [ { @@ -138,6 +137,12 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } ] roleAssignments: [ { @@ -162,4 +167,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/event-grid/topic/tests/e2e/pe/dependencies.bicep b/avm/res/event-grid/topic/tests/e2e/pe/dependencies.bicep deleted file mode 100644 index 4d31fc9282e..00000000000 --- a/avm/res/event-grid/topic/tests/e2e/pe/dependencies.bicep +++ /dev/null @@ -1,49 +0,0 @@ -@description('Optional. The location to deploy to.') -param location string = resourceGroup().location - -@description('Required. The name of the Virtual Network to create.') -param virtualNetworkName string - -var addressPrefix = '10.0.0.0/16' - -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: 'defaultSubnet' - properties: { - addressPrefix: cidrSubnet(addressPrefix, 16, 0) - } - } - ] - } -} - -resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { - name: 'privatelink.eventgrid.azure.net' - location: 'global' - - resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { - name: '${virtualNetwork.name}-vnetlink' - location: 'global' - properties: { - virtualNetwork: { - id: virtualNetwork.id - } - registrationEnabled: false - } - } -} - -@description('The resource ID of the created Virtual Network Subnet.') -output subnetResourceId string = virtualNetwork.properties.subnets[0].id - -@description('The resource ID of the created Private DNS Zone.') -output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/event-grid/topic/tests/e2e/pe/main.test.bicep b/avm/res/event-grid/topic/tests/e2e/pe/main.test.bicep deleted file mode 100644 index 95900fbe393..00000000000 --- a/avm/res/event-grid/topic/tests/e2e/pe/main.test.bicep +++ /dev/null @@ -1,73 +0,0 @@ -targetScope = 'subscription' - -metadata name = 'Using private endpoint' -metadata description = 'This instance deploys the module with the private endpoint.' - -// ========== // -// Parameters // -// ========== // - -@description('Optional. The name of the resource group to deploy for testing purposes.') -@maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-eventgrid.topics-${serviceShort}-rg' - -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location - -@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'egtpe' - -@description('Optional. A token to inject into the name of each resource.') -param namePrefix string = '#_namePrefix_#' - -// ============ // -// Dependencies // -// ============ // - -// General resources -// ================= -resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: resourceGroupName - location: resourceLocation -} - -module nestedDependencies 'dependencies.bicep' = { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' - params: { - virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' - location: resourceLocation - } -} - -// ============== // -// Test Execution // -// ============== // - -@batchSize(1) -module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { - scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' - params: { - name: '${namePrefix}${serviceShort}001' - location: resourceLocation - privateEndpoints: [ - { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] - subnetResourceId: nestedDependencies.outputs.subnetResourceId - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' - } - } - ] - tags: { - 'hidden-title': 'This is visible in the resource name' - Environment: 'Non-Prod' - Role: 'DeploymentValidation' - } - } -}] diff --git a/avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep b/avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep index 087a0bb7968..e053ff5149d 100644 --- a/avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/event-grid/topic/tests/e2e/waf-aligned/main.test.bicep @@ -128,4 +128,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' Role: 'DeploymentValidation' } } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] }] diff --git a/avm/res/event-grid/topic/version.json b/avm/res/event-grid/topic/version.json index 8def869edeb..729ac87673b 100644 --- a/avm/res/event-grid/topic/version.json +++ b/avm/res/event-grid/topic/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] -} +} \ No newline at end of file diff --git a/avm/res/insights/component/README.md b/avm/res/insights/component/README.md index a1e3ed73b68..7c9b4122d55 100644 --- a/avm/res/insights/component/README.md +++ b/avm/res/insights/component/README.md @@ -747,6 +747,7 @@ Tags of the resource. | Output | Type | Description | | :-- | :-- | :-- | | `applicationId` | string | The application ID of the application insights component. | +| `connectionString` | string | Application Insights Connection String. | | `instrumentationKey` | string | Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the application insights component. | diff --git a/avm/res/insights/component/main.bicep b/avm/res/insights/component/main.bicep index e469deb503c..26504d06762 100644 --- a/avm/res/insights/component/main.bicep +++ b/avm/res/insights/component/main.bicep @@ -185,6 +185,9 @@ output location string = appInsights.location @description('Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component.') output instrumentationKey string = appInsights.properties.InstrumentationKey +@description('Application Insights Connection String.') +output connectionString string = appInsights.properties.ConnectionString + // =============== // // Definitions // // =============== // diff --git a/avm/res/insights/component/main.json b/avm/res/insights/component/main.json index a81cf052b7d..a479a84010b 100644 --- a/avm/res/insights/component/main.json +++ b/avm/res/insights/component/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "9561238160025481382" + "templateHash": "2927135998555920691" }, "name": "Application Insights", "description": "This component deploys an Application Insights instance.", @@ -581,6 +581,13 @@ "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." }, "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" } } } \ No newline at end of file diff --git a/avm/res/insights/component/version.json b/avm/res/insights/component/version.json index 729ac87673b..76049e1c4ad 100644 --- a/avm/res/insights/component/version.json +++ b/avm/res/insights/component/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.2", + "version": "0.3", "pathFilters": [ "./main.json" ]