diff --git a/docs/CustomizingAzdParameters.md b/docs/CustomizingAzdParameters.md index b71a16a3..ef32e82d 100644 --- a/docs/CustomizingAzdParameters.md +++ b/docs/CustomizingAzdParameters.md @@ -23,6 +23,7 @@ By default this template will use the environment name as the prefix to prevent | `AZURE_ENV_COSMOS_SECONDARY_LOCATION` | string | *(not set by default)* | Specifies the secondary region for Cosmos DB. Required if `enableRedundancy` is `true`. | | `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID` | string | *(not set by default)* | Specifies the existing AI Foundry Project Resource ID if it needs to be reused. | | `AZURE_ENV_ACR_NAME` | string | `cmsacontainerreg.azurecr.io` | Specifies the Azure Container Registry name to use for container images. | +| `AZURE_ENV_VM_SIZE` | string | `Standard_D2s_v5` | Overrides the jumpbox VM size (private networking only). Default: `Standard_D2s_v5`. | --- diff --git a/docs/TroubleShootingSteps.md b/docs/TroubleShootingSteps.md index 95ebe363..0a4b8ab1 100644 --- a/docs/TroubleShootingSteps.md +++ b/docs/TroubleShootingSteps.md @@ -61,7 +61,7 @@ Use these as quick reference guides to unblock your deployments. | **ServiceQuotaExceeded** | Free tier service quota limit reached for Azure AI Search | This error occurs when you attempt to deploy an Azure AI Search service but have already reached the **free tier quota limit** for your subscription. Each Azure subscription is limited to **one free tier Search service**.

**Example error message:**
`ServiceQuotaExceeded: Operation would exceed 'free' tier service quota. You are using 1 out of 1 'free' tier service quota.`

**Common causes:**

**Resolution:**

**Reference:**
| | **InsufficientQuota** | Not enough quota available in subscription | | | **MaxNumberOfRegionalEnvironmentsInSubExceeded** | Maximum Container App Environments limit reached for region |This error occurs when you attempt to create more **Azure Container App Environments** than the regional quota limit allows for your subscription. Each Azure region has a specific limit on the number of Container App Environments that can be created per subscription.

**Common Causes:**

**Resolution:**

**Reference:**
| -| **SkuNotAvailable** | Requested SKU not available in selected location or zone | You receive this error in the following scenarios:
| +| **SkuNotAvailable** | Requested SKU not available in selected location or zone | This error occurs when the resource SKU you've selected (such as VM size) isn't available for the target location or availability zone.

**In this deployment**, the jumpbox VM defaults to `Standard_D2s_v5`. While this size is available in 60+ regions, certain regions or zones may not support it.

**Resolution:**

**Reference:**
| | **Conflict - No available instances to satisfy this request** | Azure App Service has insufficient capacity in the region | This error occurs when Azure App Service doesn't have enough available compute instances in the selected region to provision or scale your app.

**Common Causes:**

**Resolution:**

**Reference:** [Azure App Service Plans](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans) | -------------------------------- @@ -120,7 +120,7 @@ Use these as quick reference guides to unblock your deployments. |-----------------|-------------|------------------| | **NetcfgSubnetRangeOutsideVnet** | Subnet IP range outside virtual network address space | | | **DisableExport_PublicNetworkAccessMustBeDisabled** | Public network access must be disabled when export is disabled | | -| **VMSizeIsNotPermittedToEnableAcceleratedNetworking** | VM size does not support accelerated networking | This error occurs when you attempt to enable accelerated networking on a VM size that does not support it.

**How to reproduce:**

**Resolution:**
| +| **VMSizeIsNotPermittedToEnableAcceleratedNetworking** | VM size does not support accelerated networking | This error occurs when you attempt to enable accelerated networking on a VM size that does not support it. This deployment's jumpbox VM **requires** accelerated networking.

**Default VM size:** `Standard_D2s_v5` — supports accelerated networking.

**How this error happens:**

**Resolution:**
| **NetworkSecurityGroupNotCompliantForAzureBastionSubnet** / **SecurityRuleParameterContainsUnsupportedValue** | NSG rules blocking required Azure Bastion ports | This error occurs when the Network Security Group (NSG) attached to `AzureBastionSubnet` explicitly denies inbound TCP ports 443 and/or 4443, which Azure Bastion requires for management and tunneling.

**How to reproduce:**

**Resolution:**
| | **RouteTableCannotBeAttachedForAzureBastionSubnet** | Route table attached to Azure Bastion subnet | This error occurs because Azure Bastion subnet (`AzureBastionSubnet`) has a platform restriction that prevents route tables from being attached.

**How to reproduce:**

**Resolution:**
| diff --git a/infra/main.bicep b/infra/main.bicep index 31852aa0..7a55a7f9 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -637,7 +637,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.20.0' = if (e enableTelemetry: enableTelemetry computerName: take(virtualMachineResourceName, 15) osType: 'Windows' - vmSize: vmSize ?? 'Standard_D2s_v3' + vmSize: vmSize ?? 'Standard_D2s_v5' adminUsername: vmAdminUsername ?? 'JumpboxAdminUser' adminPassword: vmAdminPassword ?? 'JumpboxAdminP@ssw0rd1234!' managedIdentities: { diff --git a/infra/main.json b/infra/main.json index bf15cc8e..87283bf4 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14323896881835347609" + "version": "0.38.33.27573", + "templateHash": "467152886292252530" }, "name": "Modernize Your Code Solution Accelerator", "description": "CSA CTO Gold Standard Solution Accelerator for Modernize Your Code. \r\n" @@ -243,7 +243,11 @@ "privatelink.documents.azure.com", "privatelink.vaultcore.azure.net", "[format('privatelink.blob.{0}', environment().suffixes.storage)]", - "[format('privatelink.file.{0}', environment().suffixes.storage)]" + "[format('privatelink.file.{0}', environment().suffixes.storage)]", + "privatelink.monitor.azure.com", + "privatelink.oms.opinsights.azure.com", + "privatelink.ods.opinsights.azure.com", + "privatelink.agentsvc.azure-automation.net" ], "dnsZoneIndex": { "cognitiveServices": 0, @@ -252,7 +256,11 @@ "cosmosDB": 3, "keyVault": 4, "storageBlob": 5, - "storageFile": 6 + "storageFile": 6, + "monitor": 7, + "oms": 8, + "ods": 9, + "agentSvc": 10 }, "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", "maintenanceConfigurationResourceName": "[format('mc-{0}', variables('solutionSuffix'))]", @@ -3931,12 +3939,11 @@ "disableIpMasking": { "value": false }, - "disableLocalAuth": { - "value": true - }, "flowType": { "value": "Bluefield" - } + }, + "publicNetworkAccessForIngestion": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "publicNetworkAccessForQuery": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -4662,6 +4669,354 @@ "logAnalyticsWorkspace" ] }, + "dataCollectionEndpoint": { + "condition": "[and(parameters('enablePrivateNetworking'), parameters('enableMonitoring'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.data-collection-endpoint.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('dce-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "kind": { + "value": "Windows" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "tags": { + "value": "[variables('allTags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.31.92.45157", + "templateHash": "2803753346410103560" + }, + "name": "Data Collection Endpoints", + "description": "This module deploys a Data Collection Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the data collection endpoint. The name is case insensitive." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection endpoint." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "kind": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Optional. The kind of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. The configuration to set whether network access from public internet to the endpoints are allowed." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-datacollectionendpoint.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dataCollectionEndpoint": { + "type": "Microsoft.Insights/dataCollectionEndpoints", + "apiVersion": "2023-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + }, + "description": "[parameters('description')]" + } + }, + "dataCollectionEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/dataCollectionEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "dataCollectionEndpoint" + ] + }, + "dataCollectionEndpoint_roleAssignments": { + "copy": { + "name": "dataCollectionEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/dataCollectionEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "dataCollectionEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the dataCollectionEndpoint." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dataCollectionEndpoint." + }, + "value": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dataCollectionEndpoint was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('dataCollectionEndpoint', '2023-03-11', 'full').location]" + } + } + } + } + }, "virtualNetwork": { "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", @@ -4702,8 +5057,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "4892991135758906801" + "version": "0.38.33.27573", + "templateHash": "11189353177117695367" } }, "definitions": { @@ -10526,50 +10881,1602 @@ } }, "parameters": { - "privateDnsZoneName": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" + }, + "description": "Optional. The metadata attached to the record set." + }, + "nullable": true + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" + }, + "description": "Optional. The list of TXT records in the record set." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.37.4.10188", + "templateHash": "517173107480898390" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" + }, + "description": "Optional. Tags of the resource." + }, + "nullable": true + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "azureMonitorPrivateLinkScope": { + "condition": "[parameters('enablePrivateNetworking')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.insights.private-link-scope.{0}', variables('solutionSuffix')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('ampls-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "global" + }, + "accessModeSettings": { + "value": { + "ingestionAccessMode": "PrivateOnly", + "queryAccessMode": "PrivateOnly" + } + }, + "scopedResources": { + "value": "[concat(createArray(createObject('name', 'scoped-law', 'linkedResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value))), if(parameters('enableMonitoring'), createArray(createObject('name', 'scoped-appi', 'linkedResourceId', reference('applicationInsights').outputs.resourceId.value), createObject('name', 'scoped-dce', 'linkedResourceId', reference('dataCollectionEndpoint').outputs.resourceId.value)), createArray()))]" + }, + "privateEndpoints": { + "value": [ + { + "name": "[format('pep-ampls-{0}', variables('solutionSuffix'))]", + "subnetResourceId": "[reference('virtualNetwork').outputs.pepsSubnetResourceId.value]", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').monitor)).outputs.resourceId.value]" + }, + { + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').oms)).outputs.resourceId.value]" + }, + { + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').ods)).outputs.resourceId.value]" + }, + { + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').agentSvc)).outputs.resourceId.value]" + }, + { + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)).outputs.resourceId.value]" + } + ] + } + } + ] + }, + "tags": { + "value": "[variables('allTags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "524476480902078754" + }, + "name": "Azure Monitor Private Link Scopes", + "description": "This module deploys an Azure Monitor Private Link Scope." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "scopedResourceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private link scoped resource." + } + }, + "linkedResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scoped Azure monitor resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The scoped resource type." + } + }, + "accessModeType": { + "type": "object", + "properties": { + "exclusions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "privateEndpointConnectionName": { + "type": "string", + "metadata": { + "description": "Required. The private endpoint connection name associated to the private endpoint on which we want to apply the specific access mode settings." + } + }, + "ingestionAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "metadata": { + "description": "Required. Specifies the access mode of ingestion through the specified private endpoint connection in the exclusion." + } + }, + "queryAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "metadata": { + "description": "Required. Specifies the access mode of queries through the specified private endpoint connection in the exclusion." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of exclusions that override the default access mode settings for specific private endpoint connections. Exclusions for the current created Private endpoints can only be applied post initial provisioning." + } + }, + "ingestionAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default access mode of ingestion through associated private endpoints in scope. Default is \"Open\" if no private endpoints are configured and will be set to \"PrivateOnly\" if private endpoints are configured. Override default behaviour by explicitly providing a value." + } + }, + "queryAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default access mode of queries through associated private endpoints in scope. Default is \"Open\" if no private endpoints are configured and will be set to \"PrivateOnly\" if private endpoints are configured. Override default behaviour by explicitly providing a value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The access mode type." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the private link scope." + } + }, + "accessModeSettings": { + "$ref": "#/definitions/accessModeType", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.\n\n* Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.\n* Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the private link scope. Should be global." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "scopedResources": { + "type": "array", + "items": { + "$ref": "#/definitions/scopedResourceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for Azure Monitor Resources." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Logic App Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '87a39d53-fc1b-424a-814c-f7e04687dc9e')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Tag Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4a9ae827-6dc8-4573-8ac7-8239d42aa03f')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-privatelinkscope.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateLinkScope": { + "type": "microsoft.insights/privateLinkScopes", + "apiVersion": "2021-07-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "accessModeSettings": "[coalesce(parameters('accessModeSettings'), if(not(empty(parameters('privateEndpoints'))), createObject('ingestionAccessMode', 'PrivateOnly', 'queryAccessMode', 'PrivateOnly'), createObject('ingestionAccessMode', 'Open', 'queryAccessMode', 'Open')))]" + } + }, + "privateLinkScope_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('microsoft.insights/privateLinkScopes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateLinkScope" + ] + }, + "privateLinkScope_roleAssignments": { + "copy": { + "name": "privateLinkScope_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('microsoft.insights/privateLinkScopes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateLinkScope" + ] + }, + "privateLinkScope_scopedResource": { + "copy": { + "name": "privateLinkScope_scopedResource", + "count": "[length(coalesce(parameters('scopedResources'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateLinkScope-ScopedResource-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('scopedResources'), createArray())[copyIndex()].name]" + }, + "privateLinkScopeName": { + "value": "[parameters('name')]" + }, + "linkedResourceId": { + "value": "[coalesce(parameters('scopedResources'), createArray())[copyIndex()].linkedResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "18319290317274254807" + }, + "name": "Private Link Scope Scoped Resources", + "description": "This module deploys a Private Link Scope Scoped Resource." + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the private link scoped resource." + } + }, + "privateLinkScopeName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent private link scope. Required if the template is used in a standalone deployment." + } + }, + "linkedResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scoped Azure monitor resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/privateLinkScopes/scopedResources", + "apiVersion": "2021-07-01-preview", + "name": "[format('{0}/{1}', parameters('privateLinkScopeName'), parameters('name'))]", + "properties": { + "linkedResourceId": "[parameters('linkedResourceId')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group where the resource has been deployed." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed scopedResource." + }, + "value": "[resourceId('Microsoft.Insights/privateLinkScopes/scopedResources', parameters('privateLinkScopeName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The full name of the deployed Scoped Resource." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "privateLinkScope" + ] + }, + "privateLinkScope_privateEndpoints": { + "copy": { + "name": "privateLinkScope_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-privateLinkScope-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'subnetResourceId')), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'subnetResourceId')), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('microsoft.insights/privateLinkScopes', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('microsoft.insights/privateLinkScopes', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15954548978129725136" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "name": { + "subnetResourceId": { "type": "string", "metadata": { - "description": "Required. The name of the TXT record." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "metadata": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/metadata" - }, - "description": "Optional. The metadata attached to the record set." + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } }, - "ttl": { - "type": "int", - "defaultValue": 3600, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "txtRecords": { + "ipConfigurations": { "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/TXT@2024-06-01#properties/properties/properties/txtRecords" - }, - "description": "Optional. The list of TXT records in the record set." + "items": { + "$ref": "#/definitions/ipConfigurationType" }, - "nullable": true + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." } }, "roleAssignments": { @@ -10581,6 +12488,50 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } }, "variables": { @@ -10593,12 +12544,15 @@ ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -10606,7 +12560,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.nw-privdnszonetxt.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.10.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -10622,31 +12576,55 @@ } } }, - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "TXT": { - "type": "Microsoft.Network/privateDnsZones/TXT", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]", - "txtRecords": "[parameters('txtRecords')]" + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } } }, - "TXT_roleAssignments": { + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { "copy": { - "name": "TXT_roleAssignments", + "name": "privateEndpoint_roleAssignments", "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -10657,232 +12635,278 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "TXT" + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "5440815542537978381" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" ] } }, "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed TXT record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed TXT record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" - }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed TXT record." + "description": "The resource group the private endpoint was deployed into." }, "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "resolutionPolicy": { - "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "517173107480898390" }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link." - }, - "parameters": { - "privateDnsZoneName": { + "resourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" }, "name": { "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The name of the virtual network link." - } + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" }, "location": { "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01#properties/tags" - }, - "description": "Optional. Tags of the resource." + "description": "The location the resource was deployed into." }, - "nullable": true - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - }, - "resolutionPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." - } - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - }, - "resolutionPolicy": "[parameters('resolutionPolicy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the deployed virtual network link." + "description": "The custom DNS configurations of the private endpoint." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + "value": "[reference('privateEndpoint').customDnsConfigs]" }, - "resourceGroupName": { - "type": "string", + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "The resource group of the deployed virtual network link." + "description": "The resource IDs of the network interfaces associated with the private endpoint." }, - "value": "[resourceGroup().name]" + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" }, - "location": { + "groupId": { "type": "string", + "nullable": true, "metadata": { - "description": "The location the resource was deployed into." + "description": "The group Id for the private endpoint Group." }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" } } } }, "dependsOn": [ - "privateDnsZone" + "privateLinkScope", + "privateLinkScope_scopedResource" ] } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the private DNS zone was deployed into." + "description": "The name of the private link scope." }, - "value": "[resourceGroup().name]" + "value": "[parameters('name')]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the private DNS zone." + "description": "The resource ID of the private link scope." }, - "value": "[parameters('name')]" + "value": "[resourceId('microsoft.insights/privateLinkScopes', parameters('name'))]" }, - "resourceId": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource ID of the private DNS zone." + "description": "The resource group the private link scope was deployed into." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + "value": "[resourceGroup().name]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" + "value": "[reference('privateLinkScope', '2021-07-01-preview', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the private link scope." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } } } } }, "dependsOn": [ + "applicationInsights", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').ods)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').monitor)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').oms)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').agentSvc)]", + "dataCollectionEndpoint", + "logAnalyticsWorkspace", "virtualNetwork" ] }, @@ -13053,6 +15077,7 @@ "dataCollectionRuleProperties": { "value": { "kind": "Windows", + "dataCollectionEndpointResourceId": "[reference('dataCollectionEndpoint').outputs.resourceId.value]", "dataSources": { "performanceCounters": [ { @@ -13110,26 +15135,6 @@ ], "name": "perfCounterDataSource60" } - ], - "windowsEventLogs": [ - { - "name": "SecurityAuditEvents", - "streams": [ - "Microsoft-WindowsEvent" - ], - "eventLogName": "Security", - "eventTypes": [ - { - "eventType": "Audit Success" - }, - { - "eventType": "Audit Failure" - } - ], - "xPathQueries": [ - "Security!*[System[(EventID=4624 or EventID=4625)]]" - ] - } ] }, "destinations": { @@ -13147,9 +15152,7 @@ ], "destinations": [ "[format('la-{0}', variables('dataCollectionRulesResourceName'))]" - ], - "transformKql": "source", - "outputStream": "Microsoft-Perf" + ] } ] } @@ -14221,6 +16224,7 @@ } }, "dependsOn": [ + "dataCollectionEndpoint", "existingLogAnalyticsWorkspace", "logAnalyticsWorkspace" ] @@ -14619,7 +16623,7 @@ "value": "Windows" }, "vmSize": { - "value": "[coalesce(parameters('vmSize'), 'Standard_D2s_v3')]" + "value": "[coalesce(parameters('vmSize'), 'Standard_D2s_v5')]" }, "adminUsername": { "value": "[coalesce(parameters('vmAdminUsername'), 'JumpboxAdminUser')]" @@ -23616,8 +25620,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "15268521456197740686" + "version": "0.38.33.27573", + "templateHash": "13645014962264885823" }, "name": "AI Services and Project Module", "description": "This module creates an AI Services resource and an AI Foundry project within it. It supports private networking, OpenAI deployments, and role assignments." @@ -24957,8 +26961,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "6664885964502172426" + "version": "0.38.33.27573", + "templateHash": "14773633292567160969" } }, "definitions": { @@ -25921,7 +27925,7 @@ "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", @@ -25935,7 +27939,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -25973,7 +27977,7 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", @@ -26669,8 +28673,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14939823368517410024" + "version": "0.38.33.27573", + "templateHash": "14205022069293553223" } }, "definitions": { @@ -26823,8 +28827,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "13151306134286549002" + "version": "0.38.33.27573", + "templateHash": "12063034585175087716" } }, "definitions": { @@ -27041,8 +29045,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "6664885964502172426" + "version": "0.38.33.27573", + "templateHash": "14773633292567160969" } }, "definitions": { @@ -28005,7 +30009,7 @@ "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", @@ -28019,7 +30023,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -28057,7 +30061,7 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", @@ -28753,8 +30757,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "14939823368517410024" + "version": "0.38.33.27573", + "templateHash": "14205022069293553223" } }, "definitions": { @@ -28907,8 +30911,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "13151306134286549002" + "version": "0.38.33.27573", + "templateHash": "12063034585175087716" } }, "definitions": { @@ -29206,8 +31210,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "9525047811797133596" + "version": "0.38.33.27573", + "templateHash": "8737165639797720533" } }, "definitions": { @@ -37401,8 +39405,8 @@ }, "dependsOn": [ "appIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageFile)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageFile)]", "logAnalyticsWorkspace", "virtualNetwork" ] @@ -37451,8 +39455,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "9495092499292590311" + "version": "0.38.33.27573", + "templateHash": "7725000075924948023" } }, "definitions": { @@ -41314,8 +43318,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.40.2.10011", - "templateHash": "17583156542522410309" + "version": "0.38.33.27573", + "templateHash": "5400870525857167617" } }, "definitions": { diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index 98a1ead9..93b5eefb 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -47,6 +47,9 @@ "vmAdminPassword": { "value": "${AZURE_ENV_JUMPBOX_ADMIN_PASSWORD}" }, + "vmSize": { + "value": "${AZURE_ENV_VM_SIZE}" + }, "backendExists": { "value": "${SERVICE_BACKEND_RESOURCE_EXISTS=false}" }, diff --git a/infra/main_custom.bicep b/infra/main_custom.bicep index aa4a7553..cd34b604 100644 --- a/infra/main_custom.bicep +++ b/infra/main_custom.bicep @@ -566,7 +566,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.20.0' = if (e enableTelemetry: enableTelemetry computerName: take(virtualMachineResourceName, 15) osType: 'Windows' - vmSize: vmSize ?? 'Standard_D2s_v3' + vmSize: vmSize ?? 'Standard_D2s_v5' adminUsername: vmAdminUsername ?? 'JumpboxAdminUser' adminPassword: vmAdminPassword ?? 'JumpboxAdminP@ssw0rd1234!' managedIdentities: { diff --git a/infra/modules/virtualNetwork.bicep b/infra/modules/virtualNetwork.bicep index 54b507bc..82b158f6 100644 --- a/infra/modules/virtualNetwork.bicep +++ b/infra/modules/virtualNetwork.bicep @@ -170,10 +170,12 @@ param resourceSuffix string // VM Size Notes: // 1 B-series VMs (like Standard_B2ms) do not support accelerated networking. -// 2 Pick a VM size that does support accelerated networking (the usual jump-box candidates): -// Standard_DS2_v2 (2 vCPU, 7 GiB RAM, Premium SSD) // The most broadly available (it’s a legacy SKU supported in virtually every region). -// Standard_D2s_v3 (2 vCPU, 8 GiB RAM, Premium SSD) // next most common -// Standard_D2s_v4 (2 vCPU, 8 GiB RAM, Premium SSD) // Newest, so fewer regions available +// 2 Pick a VM size that supports accelerated networking + Premium SSD (the usual jump-box candidates): +// Standard_D2s_v5 (2 vCPU, 8 GiB RAM, Premium SSD/v2/Ultra) // DEFAULT - current-gen Intel, broad regional availability. +// Standard_D2as_v5 (2 vCPU, 8 GiB RAM, Premium SSD/Ultra) // AMD alternative, typically ~15% cheaper. +// Standard_D2s_v4 (2 vCPU, 8 GiB RAM, Premium SSD) // Previous gen, also broadly available. +// Standard_DS2_v2 (2 vCPU, 7 GiB RAM, Premium SSD) // Legacy SKU, being retired from some regions - avoid for new deployments. +// 3 A-series (Av2) is NOT suitable: no Premium SSD support, no accelerated networking. // Subnet Classless Inter-Domain Routing (CIDR) Sizing Reference Table (Best Practices) // | CIDR | # of Addresses | # of /24s | Notes | diff --git a/infra/samples/network-subnet-design.bicep b/infra/samples/network-subnet-design.bicep index 50347a91..63c90c39 100644 --- a/infra/samples/network-subnet-design.bicep +++ b/infra/samples/network-subnet-design.bicep @@ -110,7 +110,7 @@ import { jumpBoxConfigurationType } from 'network/jumpbox.bicep' @description('Optional. Configuration for the Jumpbox VM. Leave null to omit Jumpbox creation.') param jumpboxConfiguration jumpBoxConfigurationType = { name: 'vm-jumpbox-${resourcesName}' - size: 'Standard_D2s_v3' // Default size, can be overridden + size: 'Standard_D2s_v5' // Default size, can be overridden username: vmAdminUsername password: vmAdminPassword subnet: { diff --git a/infra/samples/network/network-resources.bicep b/infra/samples/network/network-resources.bicep index 7e2e8658..076d9ae1 100644 --- a/infra/samples/network/network-resources.bicep +++ b/infra/samples/network/network-resources.bicep @@ -75,7 +75,7 @@ module jumpbox 'jumpbox.bicep' = if (!empty(jumpboxConfiguration)) { params: { name: jumpboxConfiguration.?name ?? 'vm-jumpbox-${resourcesName}' vnetName: virtualNetwork.outputs.name - size: jumpboxConfiguration.?size ?? 'Standard_D2s_v3' + size: jumpboxConfiguration.?size ?? 'Standard_D2s_v5' logAnalyticsWorkspaceId: logAnalyticsWorkSpaceResourceId location: location subnet: jumpboxConfiguration.?subnet