diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index e4dfaebd..e739d864 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -146,7 +146,6 @@ jobs:
--parameters \
solutionName="${{ env.ENVIRONMENT_NAME }}" \
enablePrivateNetworking="false" \
- contentUnderstandingLocation="WestUS" \
deploymentType="GlobalStandard" \
gptModelName="gpt-5.1" \
gptModelVersion="2025-11-13" \
diff --git a/docs/CustomizingAzdParameters.md b/docs/CustomizingAzdParameters.md
index 0c3b5eca..b3fdec52 100644
--- a/docs/CustomizingAzdParameters.md
+++ b/docs/CustomizingAzdParameters.md
@@ -11,16 +11,15 @@ By default this template will use the environment name as the prefix to prevent
| -------------------------------------- | ------- | --------------------------- | ------------------------------------------------------------------------------------- |
| `AZURE_ENV_NAME` | string | `cps` | Sets the environment name prefix for all Azure resources (3-20 characters). |
| `AZURE_LOCATION` | string | `eastus2` | Sets the primary Azure region for resource deployment. Allowed: `australiaeast`, `centralus`, `eastasia`, `eastus2`, `japaneast`, `northeurope`, `southeastasia`, `uksouth`. |
-| `AZURE_ENV_CU_LOCATION` | string | `WestUS` | Sets the location for the Azure AI Content Understanding service. Allowed: `WestUS`, `SwedenCentral`, `AustraliaEast`. |
-| `AZURE_ENV_AI_SERVICE_LOCATION` | string | `eastus` | Sets the location for Azure AI Services (OpenAI) deployment. |
-| `AZURE_ENV_MODEL_DEPLOYMENT_TYPE` | string | `GlobalStandard` | Defines the model deployment type. Allowed: `Standard`, `GlobalStandard`. |
+| `AZURE_ENV_AI_SERVICE_LOCATION` | string | `eastus2` | Sets the location for Azure AI Services. This single account hosts both Azure OpenAI and Content Understanding. Allowed: `australiaeast`, `eastus`, `eastus2`, `japaneast`, `southcentralus`, `southeastasia`, `swedencentral`, `uksouth`, `westeurope`, `westus`, `westus3`. |
+| `AZURE_ENV_MODEL_DEPLOYMENT_TYPE` | string | `GlobalStandard` | Defines the model deployment type. Allowed: `Standard`, `GlobalStandard`.
**Note:** the `azd` location-picker filters regions using the `usageName` metadata on `azureAiServiceLocation` in `infra/main.bicep` (currently `OpenAI.GlobalStandard.gpt-5.1,300`). If you set this parameter to `Standard`, also edit that metadata to `OpenAI.Standard.gpt-5.1,300` so the picker shows the correct subset of regions. |
| `AZURE_ENV_GPT_MODEL_NAME` | string | `gpt-5.1` | Specifies the GPT model name. Default: `gpt-5.1`. |
| `AZURE_ENV_GPT_MODEL_VERSION` | string | `2025-11-13` | Specifies the GPT model version. |
| `AZURE_ENV_GPT_MODEL_CAPACITY` | integer | `300` | Sets the model capacity (minimum 1). Default: 300. Optimal: 500 for multi-document claim processing. |
| `AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT` | string | `cpscontainerreg.azurecr.io` | Sets the public container image endpoint for pulling pre-built images. |
| `AZURE_ENV_IMAGETAG` | string | `latest_v2` | Sets the container image tag (e.g., `latest_v2`, `dev`, `demo`, `hotfix`). |
-| `AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID` | string | Guide to get your [Existing Workspace Resource ID](/docs/re-use-log-analytics.md) | Reuses an existing Log Analytics Workspace instead of provisioning a new one. |
-| `AZURE_EXISTING_AIPROJECT_RESOURCE_ID` | string | Guide to get your [Existing AI Project Resource ID](/docs/re-use-foundry-project.md) | Reuses an existing AI Foundry and AI Foundry Project instead of creating a new one. |
+| `AZURE_ENV_EXISTING_LOG_ANALYTICS_WORKSPACE_RID` | string | Guide to get your [Existing Workspace Resource ID](re-use-log-analytics.md) | Reuses an existing Log Analytics Workspace instead of provisioning a new one. |
+| `AZURE_EXISTING_AIPROJECT_RESOURCE_ID` | string | Guide to get your [Existing AI Project Resource ID](re-use-foundry-project.md) | Reuses an existing AI Foundry and AI Foundry Project instead of creating a new one. |
| `AZURE_ENV_VM_SIZE` | string | `Standard_D2s_v5` | Overrides the jumpbox VM size (private networking only). Default: `Standard_D2s_v5`. |
## How to Set a Parameter
diff --git a/docs/LocalDevelopmentSetup.md b/docs/LocalDevelopmentSetup.md
index 38d868e4..7095cd7d 100644
--- a/docs/LocalDevelopmentSetup.md
+++ b/docs/LocalDevelopmentSetup.md
@@ -160,7 +160,7 @@ Example resource names from deployment:
- App Configuration: `appcs-{suffix}.azconfig.io`
- Cosmos DB: `cosmos-{suffix}.documents.azure.com`
- Storage Account: `st{suffix}.queue.core.windows.net`
-- Content Understanding: `aicu-{suffix}.cognitiveservices.azure.com`
+- Content Understanding: `aif-{suffix}.cognitiveservices.azure.com`
### Required Azure RBAC Permissions
diff --git a/docs/TroubleShootingSteps.md b/docs/TroubleShootingSteps.md
index 6d4d60cd..3f78e276 100644
--- a/docs/TroubleShootingSteps.md
+++ b/docs/TroubleShootingSteps.md
@@ -128,7 +128,7 @@ Use these as quick reference guides to unblock your deployments.
| **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:**
- In `virtualNetwork.bicep`, add `attachRouteTable: true` to the `AzureBastionSubnet` configuration:
`{ name: 'AzureBastionSubnet', addressPrefixes: ['10.0.10.0/26'], attachRouteTable: true }` - Add a Route Table module to the template
- Update subnet creation to attach route table conditionally:
`routeTableResourceId: subnet.?attachRouteTable == true ? routeTable.outputs.resourceId : null` - Deploy the template → Azure throws `RouteTableCannotBeAttachedForAzureBastionSubnet`
**Resolution:**
- Remove the `attachRouteTable: true` flag from `AzureBastionSubnet` configuration
- Ensure no route table is associated with `AzureBastionSubnet`
- Route tables can only be attached to other subnets, not `AzureBastionSubnet`
- For more details, refer to [Azure Bastion subnet requirements](https://learn.microsoft.com/en-us/azure/bastion/configuration-settings#subnet)
|
| **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:**
- You override the VM size (via `AZURE_ENV_VM_SIZE`) with a size that doesn't support accelerated networking (e.g., `Standard_A2m_v2`, A-series, or B-series VMs)
- Azure rejects the deployment with `VMSizeIsNotPermittedToEnableAcceleratedNetworking`
**Resolution:**
- Use the default `Standard_D2s_v5` (recommended)
- If overriding VM size, choose one that supports accelerated networking:
`Standard_D2s_v4`, `Standard_D2as_v5` (AMD), `Standard_D2s_v3` - Verify VM size supports accelerated networking:
`az vm list-skus --location --size --query "[?capabilities[?name=='AcceleratedNetworkingEnabled' && value=='True']]"` - Avoid A-series and B-series VMs — they do not support accelerated networking
- See [VM sizes with accelerated networking](https://learn.microsoft.com/en-us/azure/virtual-network/accelerated-networking-overview)
|
| **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:**
- Deploy the template with `enablePrivateNetworking=true` so the virtualNetwork module creates `AzureBastionSubnet` and a Network Security Group that denies ports 443 and 4443
- Attempt to deploy Azure Bastion into that subnet
- During validation, Bastion detects the deny rules and fails with `NetworkSecurityGroupNotCompliantForAzureBastionSubnet`
**Resolution:**
- **Remove or modify deny rules** for ports 443 and 4443 in the NSG attached to `AzureBastionSubnet`
- **Ensure required inbound rules** per [Azure Bastion NSG requirements](https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg)
- **Use Bicep conditions** to skip NSG attachments for `AzureBastionSubnet` if deploying Bastion
- **Validate the NSG configuration** before deploying Bastion into the subnet
|
-| **403 Forbidden - Content Understanding** | Azure AI Content Understanding returns 403 Forbidden in WAF (private networking) deployment | This error occurs when the **Azure AI Content Understanding** service returns a `403 Forbidden` response during document processing in a **WAF-enabled (private networking)** deployment.
**Why this happens:**
In WAF deployments (`enablePrivateNetworking=true`), the Content Understanding AI Services account (`aicu-`) is configured with `publicNetworkAccess: Disabled`. All traffic must flow through the **private endpoint** (`pep-aicu-`) and resolve via private DNS zones (`privatelink.cognitiveservices.azure.com`, `privatelink.services.ai.azure.com`, `privatelink.contentunderstanding.ai.azure.com`). If any part of this chain is misconfigured, the request either reaches the public endpoint (which is blocked) or fails to route entirely, resulting in a 403.
**Common causes:**
- Private DNS zones not linked to the VNet — DNS resolution falls back to the public IP, which is blocked
- Private endpoint connection is not in **Approved** state
- Content Understanding is deployed in a different region (`contentUnderstandingLocation`, defaults to `WestUS`) than the main deployment — the private endpoint still works cross-region, but DNS misconfiguration is more likely
- Container Apps are not injected into the VNet or are on a subnet that cannot reach the private endpoint
- Managed Identity used by the Container App does not have the required **Cognitive Services User** role on the Content Understanding resource
**Resolution:**
- **Verify private endpoint status:**
`az network private-endpoint show --name pep-aicu- --resource-group --query "privateLinkServiceConnections[0].privateLinkServiceConnectionState.status"`
Expected: `Approved` - **Verify private DNS zone VNet links:**
`az network private-dns zone list --resource-group -o table`
Ensure `privatelink.cognitiveservices.azure.com`, `privatelink.services.ai.azure.com`, and `privatelink.contentunderstanding.ai.azure.com` all have VNet links - **Test DNS resolution from the jumpbox VM** (inside the VNet):
`nslookup aicu-.cognitiveservices.azure.com`
Should resolve to a private IP (e.g., `10.x.x.x`), NOT a public IP - **Verify RBAC role assignments:** Ensure the Container App managed identity has **Cognitive Services User** role on the Content Understanding resource:
`az role assignment list --scope /subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts/aicu- --query "[?roleDefinitionName=='Cognitive Services User']" -o table` - **Check Container App VNet integration:** Confirm the Container App Environment is deployed into the VNet and can reach the backend subnet where the private endpoint resides
- **Redeploy if needed:**
`azd up`
**Reference:**
- [Configure private endpoints for Azure AI Services](https://learn.microsoft.com/en-us/azure/ai-services/cognitive-services-virtual-networks)
- [Azure Private DNS zones](https://learn.microsoft.com/en-us/azure/dns/private-dns-overview)
|
+| **403 Forbidden - Content Understanding** | Azure AI Content Understanding returns 403 Forbidden in WAF (private networking) deployment | This error occurs when the **Azure AI Content Understanding** API on the unified AI Services account (`aif-`) returns a `403 Forbidden` response during document processing in a **WAF-enabled (private networking)** deployment.
**Why this happens:**
As of the CU GA migration, Content Understanding shares the same Azure AI Services account as Azure OpenAI (`aif-`). In WAF deployments (`enablePrivateNetworking=true`), that account is configured with `publicNetworkAccess: Disabled`. All traffic must flow through the unified private endpoint (`pep-aiservices-`) and resolve via four private DNS zones: `privatelink.cognitiveservices.azure.com`, `privatelink.openai.azure.com`, `privatelink.services.ai.azure.com`, and `privatelink.contentunderstanding.ai.azure.com`. If any link in this chain is misconfigured, the request either reaches the public endpoint (blocked) or fails to route, resulting in a 403.
**Common causes:**
- Private DNS zones not linked to the VNet — DNS resolution falls back to the public IP, which is blocked
- Private endpoint connection is not in **Approved** state
- Container Apps are not injected into the VNet or are on a subnet that cannot reach the private endpoint
- Managed Identity used by the Container App does not have the required **Cognitive Services User** role on the unified AI Services account
- Reusing an existing AI Foundry project (`existingFoundryProjectResourceId`): the repo no longer creates a CU-specific PE; the existing account must have its own private endpoint covering the four DNS zones above
**Resolution:**
- **Verify private endpoint status:**
`az network private-endpoint show --name pep-aiservices- --resource-group --query "privateLinkServiceConnections[0].privateLinkServiceConnectionState.status"`
Expected: `Approved` - **Verify private DNS zone VNet links:**
`az network private-dns zone list --resource-group -o table`
Ensure `privatelink.cognitiveservices.azure.com`, `privatelink.openai.azure.com`, `privatelink.services.ai.azure.com`, and `privatelink.contentunderstanding.ai.azure.com` all have VNet links - **Test DNS resolution from the jumpbox VM** (inside the VNet):
`nslookup aif-.cognitiveservices.azure.com`
Should resolve to a private IP (e.g., `10.x.x.x`), NOT a public IP - **Verify RBAC role assignments:** ensure the Container App managed identity has **Cognitive Services User** role on the unified account:
`az role assignment list --scope /subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts/aif- --query "[?roleDefinitionName=='Cognitive Services User']" -o table` - **Check Container App VNet integration:** confirm the Container App Environment is deployed into the VNet and can reach the backend subnet where the private endpoint resides
- **Redeploy if needed:**
`azd up`
**Reference:**
- [Configure private endpoints for Azure AI Services](https://learn.microsoft.com/en-us/azure/ai-services/cognitive-services-virtual-networks)
- [Azure Private DNS zones](https://learn.microsoft.com/en-us/azure/dns/private-dns-overview)
|
---------------------------------
diff --git a/docs/re-use-foundry-project.md b/docs/re-use-foundry-project.md
index 8c7ff463..b02181c0 100644
--- a/docs/re-use-foundry-project.md
+++ b/docs/re-use-foundry-project.md
@@ -1,7 +1,14 @@
-[← Back to *DEPLOYMENT* guide](/docs/DeploymentGuide.md#deployment-options--steps)
+[← Back to *DEPLOYMENT* guide](./DeploymentGuide.md#deployment-options--steps)
# Reusing an Existing Azure AI Foundry Project
To configure your environment to use an existing Azure AI Foundry Project, follow these steps:
+
+> **⚠️ Region requirement**
+>
+> The existing Foundry project must reside in a region that supports **both** the GPT model deployed by this accelerator (default `gpt-5.1` with `GlobalStandard` deployment type) **and** Azure AI Content Understanding (GA).
+> Supported regions: `australiaeast`, `eastus`, `eastus2`, `japaneast`, `southcentralus`, `southeastasia`, `swedencentral`, `uksouth`, `westeurope`, `westus`, `westus3`.
+> If the existing project is in a different region, deployment will fail or the application will not work correctly.
+
---
### 1. Go to Azure Portal
Go to https://portal.azure.com
@@ -41,4 +48,4 @@ azd env set AZURE_EXISTING_AIPROJECT_RESOURCE_ID '` with the value obtained from Step 5.
### 7. Continue Deployment
-Proceed with the next steps in the [deployment guide](/docs/DeploymentGuide.md#deployment-options--steps).
+Proceed with the next steps in the [deployment guide](./DeploymentGuide.md#deployment-options--steps).
diff --git a/infra/main.bicep b/infra/main.bicep
index b06f22c5..2bc2b88c 100644
--- a/infra/main.bicep
+++ b/infra/main.bicep
@@ -25,26 +25,20 @@ param solutionName string = 'cps'
param location string
@minLength(1)
-@description('Optional. Location for the Azure AI Content Understanding service deployment.')
-@allowed(['WestUS', 'SwedenCentral', 'AustraliaEast'])
-@metadata({
- azd: {
- type: 'location'
- }
-})
-param contentUnderstandingLocation string = 'WestUS'
-
@allowed([
'australiaeast'
- 'centralus'
- 'eastasia'
+ 'eastus'
'eastus2'
'japaneast'
- 'northeurope'
+ 'southcentralus'
'southeastasia'
+ 'swedencentral'
'uksouth'
+ 'westeurope'
+ 'westus'
+ 'westus3'
])
-@description('Required. Location for the Azure AI Services deployment.')
+@description('Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead.')
@metadata({
azd: {
type: 'location'
@@ -747,6 +741,16 @@ module avmAiServices 'modules/account/aifoundry.bicep' = {
roleDefinitionIdOrName: 'Azure AI Developer'
principalType: 'ServicePrincipal'
}
+ {
+ principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId!
+ roleDefinitionIdOrName: 'Cognitive Services User'
+ principalType: 'ServicePrincipal'
+ }
+ {
+ principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId!
+ roleDefinitionIdOrName: 'Cognitive Services User'
+ principalType: 'ServicePrincipal'
+ }
]
networkAcls: {
bypass: 'AzureServices'
@@ -816,84 +820,6 @@ module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoi
}
}
-module avmAiServices_cu 'br/public:avm/res/cognitive-services/account:0.14.2' = {
- name: take('avm.res.cognitive-services.account.content-understanding.${solutionSuffix}', 64)
-
- params: {
- name: 'aicu-${solutionSuffix}'
- location: contentUnderstandingLocation
- sku: 'S0'
- managedIdentities: {
- systemAssigned: false
- userAssignedResourceIds: [
- avmManagedIdentity.outputs.resourceId // Use the managed identity created above
- ]
- }
- kind: 'AIServices'
- tags: {
- app: solutionSuffix
- location: location
- }
- customSubDomainName: 'aicu-${solutionSuffix}'
- disableLocalAuth: true
- enableTelemetry: enableTelemetry
- networkAcls: {
- bypass: 'AzureServices'
- defaultAction: 'Allow' // Always allow for AI Services
- }
- roleAssignments: [
- {
- principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId!
- roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908'
- principalType: 'ServicePrincipal'
- }
- {
- principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId!
- roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908'
- principalType: 'ServicePrincipal'
- }
- ]
-
- publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled'
- }
-}
-
-module contentUnderstandingPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking) {
- name: take('avm.res.network.private-endpoint.aicu-${solutionSuffix}', 64)
- params: {
- name: 'pep-aicu-${solutionSuffix}'
- location: location
- tags: tags
- customNetworkInterfaceName: 'nic-aicu-${solutionSuffix}'
- privateLinkServiceConnections: [
- {
- name: 'pep-aicu-${solutionSuffix}-cognitiveservices-connection'
- properties: {
- privateLinkServiceId: avmAiServices_cu.outputs.resourceId
- groupIds: ['account']
- }
- }
- ]
- privateDnsZoneGroup: {
- privateDnsZoneGroupConfigs: [
- {
- name: 'aicu-dns-zone-cognitiveservices'
- privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId
- }
- {
- name: 'ai-services-dns-zone-aiservices'
- privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId
- }
- {
- name: 'aicu-dns-zone-contentunderstanding'
- privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId
- }
- ]
- }
- subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId
- }
-}
-
// ========== Container App Environment ========== //
module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = {
name: take('avm.res.app.managed-environment.${solutionSuffix}', 64)
@@ -1408,7 +1334,7 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9
}
{
name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT'
- value: avmAiServices_cu.outputs.endpoint //TODO: replace with actual endpoint
+ value: avmAiServices.outputs.endpoint
}
{
name: 'APP_COSMOS_CONTAINER_PROCESS'
@@ -1683,7 +1609,6 @@ module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = {
}
dependsOn: [
cognitiveServicePrivateEndpoint
- contentUnderstandingPrivateEndpoint
]
}
@@ -1922,8 +1847,8 @@ output CONTAINER_REGISTRY_NAME string = avmContainerRegistry.outputs.name
@description('The login server of the Azure Container Registry.')
output CONTAINER_REGISTRY_LOGIN_SERVER string = avmContainerRegistry.outputs.loginServer
-@description('The name of the Content Understanding AI Services account.')
-output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices_cu.outputs.name
+@description('The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA.')
+output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices.outputs.name
@description('The resource group the resources were deployed into.')
output AZURE_RESOURCE_GROUP string = resourceGroup().name
diff --git a/infra/main.json b/infra/main.json
index 1c3e3e3e..b66d5b32 100644
--- a/infra/main.json
+++ b/infra/main.json
@@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.42.1.51946",
- "templateHash": "2184176346978633067"
+ "templateHash": "312988678863218513"
},
"name": "Content Processing Solution Accelerator",
"description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance."
@@ -40,33 +40,20 @@
"description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)."
}
},
- "contentUnderstandingLocation": {
- "type": "string",
- "defaultValue": "WestUS",
- "allowedValues": [
- "WestUS",
- "SwedenCentral",
- "AustraliaEast"
- ],
- "metadata": {
- "azd": {
- "type": "location"
- },
- "description": "Optional. Location for the Azure AI Content Understanding service deployment."
- },
- "minLength": 1
- },
"azureAiServiceLocation": {
"type": "string",
"allowedValues": [
"australiaeast",
- "centralus",
- "eastasia",
+ "eastus",
"eastus2",
"japaneast",
- "northeurope",
+ "southcentralus",
"southeastasia",
- "uksouth"
+ "swedencentral",
+ "uksouth",
+ "westeurope",
+ "westus",
+ "westus3"
],
"metadata": {
"azd": {
@@ -75,8 +62,9 @@
"OpenAI.GlobalStandard.gpt-5.1,300"
]
},
- "description": "Required. Location for the Azure AI Services deployment."
- }
+ "description": "Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead."
+ },
+ "minLength": 1
},
"deploymentType": {
"type": "string",
@@ -7485,6 +7473,13 @@
"description": "Optional. Storage account boot diagnostic base URI."
}
},
+ "proximityPlacementGroupResourceId": {
+ "type": "string",
+ "defaultValue": "",
+ "metadata": {
+ "description": "Optional. Resource ID of a proximity placement group."
+ }
+ },
"virtualMachineScaleSetResourceId": {
"type": "string",
"defaultValue": "",
@@ -8075,6 +8070,7 @@
},
"applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]",
"availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]",
+ "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]",
"virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]",
"priority": "[parameters('priority')]",
"evictionPolicy": "[if(and(not(empty(parameters('priority'))), not(equals(parameters('priority'), 'Regular'))), parameters('evictionPolicy'), null())]",
@@ -36261,6 +36257,16 @@
"principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]",
"roleDefinitionIdOrName": "Azure AI Developer",
"principalType": "ServicePrincipal"
+ },
+ {
+ "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]",
+ "roleDefinitionIdOrName": "Cognitive Services User",
+ "principalType": "ServicePrincipal"
+ },
+ {
+ "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]",
+ "roleDefinitionIdOrName": "Cognitive Services User",
+ "principalType": "ServicePrincipal"
}
]
},
@@ -42475,17 +42481,17 @@
},
"dependsOn": [
"avmAiServices",
- "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]",
- "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]",
- "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]",
+ "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]",
+ "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]",
+ "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]",
"virtualNetwork"
]
},
- "avmAiServices_cu": {
+ "avmContainerAppEnv": {
"type": "Microsoft.Resources/deployments",
"apiVersion": "2025-04-01",
- "name": "[take(format('avm.res.cognitive-services.account.content-understanding.{0}', variables('solutionSuffix')), 64)]",
+ "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
@@ -42493,61 +42499,42 @@
"mode": "Incremental",
"parameters": {
"name": {
- "value": "[format('aicu-{0}', variables('solutionSuffix'))]"
+ "value": "[format('cae-{0}', variables('solutionSuffix'))]"
},
"location": {
- "value": "[parameters('contentUnderstandingLocation')]"
+ "value": "[parameters('location')]"
},
- "sku": {
- "value": "S0"
+ "tags": {
+ "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]"
},
"managedIdentities": {
"value": {
- "systemAssigned": false,
- "userAssignedResourceIds": [
- "[reference('avmManagedIdentity').outputs.resourceId.value]"
- ]
- }
- },
- "kind": {
- "value": "AIServices"
- },
- "tags": {
- "value": {
- "app": "[variables('solutionSuffix')]",
- "location": "[parameters('location')]"
+ "systemAssigned": true
}
},
- "customSubDomainName": {
- "value": "[format('aicu-{0}', variables('solutionSuffix'))]"
- },
- "disableLocalAuth": {
- "value": true
+ "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]",
+ "workloadProfiles": {
+ "value": [
+ {
+ "name": "Consumption",
+ "workloadProfileType": "Consumption"
+ }
+ ]
},
"enableTelemetry": {
"value": "[parameters('enableTelemetry')]"
},
- "networkAcls": {
- "value": {
- "bypass": "AzureServices",
- "defaultAction": "Allow"
- }
+ "publicNetworkAccess": {
+ "value": "Enabled"
},
- "roleAssignments": {
- "value": [
- {
- "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]",
- "roleDefinitionIdOrName": "a97b65f3-24c7-4388-baec-2e87135dc908",
- "principalType": "ServicePrincipal"
- },
- {
- "principalId": "[reference('avmContainerApp_Workflow').outputs.systemAssignedMIPrincipalId.value]",
- "roleDefinitionIdOrName": "a97b65f3-24c7-4388-baec-2e87135dc908",
- "principalType": "ServicePrincipal"
- }
- ]
+ "platformReservedCidr": {
+ "value": "172.17.17.0/24"
},
- "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]"
+ "platformReservedDnsIP": {
+ "value": "172.17.17.17"
+ },
+ "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]",
+ "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.containersSubnetResourceId.value), createObject('value', null()))]"
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
@@ -42556,3385 +42543,201 @@
"metadata": {
"_generator": {
"name": "bicep",
- "version": "0.41.2.15936",
- "templateHash": "8642151282041103672"
+ "version": "0.42.1.51946",
+ "templateHash": "11924518395502120940"
},
- "name": "Cognitive Services",
- "description": "This module deploys a Cognitive Service."
+ "name": "App ManagedEnvironments",
+ "description": "This module deploys an App Managed Environment (also known as a Container App Environment)."
},
"definitions": {
- "privateEndpointOutputType": {
+ "certificateType": {
"type": "object",
"properties": {
"name": {
"type": "string",
+ "nullable": true,
"metadata": {
- "description": "The name of the private endpoint."
- }
- },
- "resourceId": {
- "type": "string",
- "metadata": {
- "description": "The resource ID of the private endpoint."
+ "description": "Optional. The name of the certificate."
}
},
- "groupId": {
+ "certificateType": {
"type": "string",
+ "allowedValues": [
+ "ImagePullTrustedCA",
+ "ServerSSLCertificate"
+ ],
"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."
+ "description": "Optional. The type of the certificate."
}
},
- "networkInterfaceResourceIds": {
- "type": "array",
- "items": {
- "type": "string"
- },
- "metadata": {
- "description": "The IDs of the network interfaces associated with the private endpoint."
- }
- }
- },
- "metadata": {
- "__bicep_export!": true,
- "description": "The type for the private endpoint output."
- }
- },
- "deploymentType": {
- "type": "object",
- "properties": {
- "name": {
+ "certificateValue": {
"type": "string",
"nullable": true,
"metadata": {
- "description": "Optional. Specify the name of cognitive service account deployment."
+ "description": "Optional. The value of the certificate. PFX or PEM blob."
}
},
- "model": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "Required. The name of Cognitive Services account deployment model."
- }
- },
- "format": {
- "type": "string",
- "metadata": {
- "description": "Required. The format of Cognitive Services account deployment model."
- }
- },
- "version": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Conditional. The version of Cognitive Services account deployment model. Required if the model does not have a default version."
- }
- }
- },
+ "certificatePassword": {
+ "type": "securestring",
+ "nullable": true,
"metadata": {
- "description": "Required. Properties of Cognitive Services account deployment model."
+ "description": "Optional. The password of the certificate."
}
},
- "sku": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "Required. The name of the resource model definition representing SKU."
- }
- },
- "capacity": {
- "type": "int",
- "nullable": true,
- "metadata": {
- "description": "Optional. The capacity of the resource model definition representing SKU."
- }
- },
- "tier": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The tier of the resource model definition representing SKU."
- }
- },
- "size": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The size of the resource model definition representing SKU."
- }
- },
- "family": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The family of the resource model definition representing SKU."
- }
- }
- },
+ "certificateKeyVaultProperties": {
+ "$ref": "#/definitions/certificateKeyVaultPropertiesType",
"nullable": true,
"metadata": {
- "description": "Optional. The resource model definition representing SKU."
+ "description": "Optional. A key vault reference."
}
},
- "raiPolicyName": {
+ "location": {
"type": "string",
"nullable": true,
"metadata": {
- "description": "Optional. The name of RAI policy."
+ "description": "Optional. The location for the resource."
}
},
- "versionUpgradeOption": {
- "type": "string",
- "nullable": true,
+ "tags": {
+ "type": "object",
"metadata": {
- "description": "Optional. The version upgrade option."
- }
+ "__bicep_resource_derived_type!": {
+ "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags"
+ },
+ "description": "Optional. Tags of the resource."
+ },
+ "nullable": true
}
},
"metadata": {
"__bicep_export!": true,
- "description": "The type for a cognitive services account deployment."
+ "description": "The type for a certificate."
}
},
- "endpointType": {
+ "storageType": {
"type": "object",
"properties": {
- "name": {
+ "accessMode": {
"type": "string",
- "nullable": true,
+ "allowedValues": [
+ "ReadOnly",
+ "ReadWrite"
+ ],
"metadata": {
- "description": "Type of the endpoint."
+ "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"."
}
},
- "endpoint": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "The endpoint URI."
- }
- }
- },
- "metadata": {
- "__bicep_export!": true,
- "description": "The type for a cognitive services account endpoint."
- }
- },
- "secretsExportConfigurationType": {
- "type": "object",
- "properties": {
- "keyVaultResourceId": {
+ "kind": {
"type": "string",
+ "allowedValues": [
+ "NFS",
+ "SMB"
+ ],
"metadata": {
- "description": "Required. The key vault name where to store the keys and connection strings generated by the modules."
+ "description": "Required. Type of storage: \"SMB\" or \"NFS\"."
}
},
- "accessKey1Name": {
+ "storageAccountName": {
"type": "string",
- "nullable": true,
"metadata": {
- "description": "Optional. The name for the accessKey1 secret to create."
+ "description": "Required. Storage account name."
}
},
- "accessKey2Name": {
+ "name": {
"type": "string",
- "nullable": true,
"metadata": {
- "description": "Optional. The name for the accessKey2 secret to create."
+ "description": "Required. File share name."
}
}
},
"metadata": {
"__bicep_export!": true,
- "description": "The type of the secrets exported to the provided Key Vault."
+ "description": "The type of the storage."
}
},
- "commitmentPlanType": {
+ "appLogsConfigurationType": {
"type": "object",
- "properties": {
- "autoRenew": {
- "type": "bool",
- "metadata": {
- "description": "Required. Whether the plan should auto-renew at the end of the current commitment period."
- }
- },
- "current": {
- "type": "object",
- "properties": {
- "count": {
- "type": "int",
- "metadata": {
- "description": "Required. The number of committed instances (e.g., number of containers or cores)."
- }
- },
- "tier": {
- "type": "string",
- "metadata": {
- "description": "Required. The tier of the commitment plan (e.g., T1, T2)."
- }
- }
- },
- "metadata": {
- "description": "Required. The current commitment configuration."
- }
- },
- "hostingModel": {
- "type": "string",
- "metadata": {
- "description": "Required. The hosting model for the commitment plan. (e.g., DisconnectedContainer, ConnectedContainer, ProvisionedWeb, Web)."
- }
- },
- "planType": {
- "type": "string",
- "metadata": {
- "description": "Required. The plan type indicating which capability the plan applies to (e.g., NTTS, STT, CUSTOMSTT, ADDON)."
- }
- },
- "commitmentPlanGuid": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The unique identifier of an existing commitment plan to update. Set to null to create a new plan."
- }
- },
- "next": {
- "type": "object",
- "properties": {
- "count": {
- "type": "int",
- "metadata": {
- "description": "Required. The number of committed instances for the next period."
- }
- },
- "tier": {
- "type": "string",
- "metadata": {
- "description": "Required. The tier for the next commitment period."
- }
- }
+ "discriminator": {
+ "propertyName": "destination",
+ "mapping": {
+ "azure-monitor": {
+ "$ref": "#/definitions/appLogsConfigurationMonitorType"
},
- "nullable": true,
- "metadata": {
- "description": "Optional. The configuration of the next commitment period, if scheduled."
+ "log-analytics": {
+ "$ref": "#/definitions/appLogsConfigurationLawType"
}
}
},
"metadata": {
"__bicep_export!": true,
- "description": "The type for a disconnected container commitment plan."
+ "description": "The type for the App Logs Configuration."
}
},
- "networkInjectionType": {
+ "appLogsConfigurationMonitorType": {
"type": "object",
"properties": {
- "scenario": {
+ "destination": {
"type": "string",
"allowedValues": [
- "agent",
- "none"
+ "azure-monitor"
],
"metadata": {
- "description": "Required. The scenario for the network injection."
+ "description": "Required. The destination of the logs."
}
- },
- "subnetResourceId": {
+ }
+ },
+ "metadata": {
+ "description": "The type for the App Logs Configuration if using azure-monitor."
+ }
+ },
+ "appLogsConfigurationLawType": {
+ "type": "object",
+ "properties": {
+ "destination": {
"type": "string",
+ "allowedValues": [
+ "log-analytics"
+ ],
"metadata": {
- "description": "Required. The Resource ID of the subnet on the Virtual Network on which to inject."
+ "description": "Required. The destination of the logs."
}
},
- "useMicrosoftManagedNetwork": {
- "type": "bool",
- "nullable": true,
+ "logAnalyticsWorkspaceResourceId": {
+ "type": "string",
"metadata": {
- "description": "Optional. Whether to use Microsoft Managed Network. Defaults to false."
+ "description": "Required. Existing Log Analytics Workspace resource ID."
}
}
},
"metadata": {
- "__bicep_export!": true,
- "description": "Type for network configuration in AI Foundry where virtual network injection occurs to secure scenarios like Agents entirely within a private network."
+ "description": "The type for the App Logs Configuration if using log-analytics."
}
},
- "_1.secretSetOutputType": {
+ "certificateKeyVaultPropertiesType": {
"type": "object",
"properties": {
- "secretResourceId": {
- "type": "string",
- "metadata": {
- "description": "The resourceId of the exported secret."
- }
- },
- "secretUri": {
+ "identityResourceId": {
"type": "string",
"metadata": {
- "description": "The secret URI of the exported secret."
+ "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault."
}
},
- "secretUriWithVersion": {
+ "keyVaultUrl": {
"type": "string",
"metadata": {
- "description": "The secret URI with version of the exported secret."
+ "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain."
}
}
},
"metadata": {
- "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.",
+ "description": "The type for the certificate's key vault properties.",
"__bicep_imported_from!": {
- "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0"
+ "sourceTemplate": "certificate/main.bicep"
}
}
},
- "_2.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."
- }
- },
- "notes": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Specify the notes of the 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.6.1"
- }
- }
- },
- "_2.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.6.1"
- }
- }
- },
- "_2.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.6.1"
- }
- }
- },
- "_2.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.6.1"
- }
- }
- },
- "_2.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.6.1"
- }
- }
- },
- "customerManagedKeyType": {
- "type": "object",
- "properties": {
- "keyVaultResourceId": {
- "type": "string",
- "metadata": {
- "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from."
- }
- },
- "keyName": {
- "type": "string",
- "metadata": {
- "description": "Required. The name of the customer managed key to use for encryption."
- }
- },
- "keyVersion": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time."
- }
- },
- "userAssignedIdentityResourceId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use."
- }
- }
- },
- "metadata": {
- "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.",
- "__bicep_imported_from!": {
- "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0"
- }
- }
- },
- "diagnosticSettingFullType": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The name of the diagnostic setting."
- }
- },
- "logCategoriesAndGroups": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "category": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here."
- }
- },
- "categoryGroup": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs."
- }
- },
- "enabled": {
- "type": "bool",
- "nullable": true,
- "metadata": {
- "description": "Optional. Enable or disable the category explicitly. Default is `true`."
- }
- }
- }
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection."
- }
- },
- "metricCategories": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "category": {
- "type": "string",
- "metadata": {
- "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics."
- }
- },
- "enabled": {
- "type": "bool",
- "nullable": true,
- "metadata": {
- "description": "Optional. Enable or disable the category explicitly. Default is `true`."
- }
- }
- }
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection."
- }
- },
- "logAnalyticsDestinationType": {
- "type": "string",
- "allowedValues": [
- "AzureDiagnostics",
- "Dedicated"
- ],
- "nullable": true,
- "metadata": {
- "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type."
- }
- },
- "workspaceResourceId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub."
- }
- },
- "storageAccountResourceId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub."
- }
- },
- "eventHubAuthorizationRuleResourceId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to."
- }
- },
- "eventHubName": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub."
- }
- },
- "marketplacePartnerResourceId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs."
- }
- }
- },
- "metadata": {
- "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.",
- "__bicep_imported_from!": {
- "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0"
- }
- }
- },
- "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."
- }
- },
- "notes": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Specify the notes of the 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.6.0"
- }
- }
- },
- "managedIdentityAllType": {
- "type": "object",
- "properties": {
- "systemAssigned": {
- "type": "bool",
- "nullable": true,
- "metadata": {
- "description": "Optional. Enables system assigned managed identity on the resource."
- }
- },
- "userAssignedResourceIds": {
- "type": "array",
- "items": {
- "type": "string"
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption."
- }
- }
- },
- "metadata": {
- "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.",
- "__bicep_imported_from!": {
- "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0"
- }
- }
- },
- "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/_2.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/_2.privateEndpointCustomDnsConfigType"
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. Custom DNS configurations."
- }
- },
- "ipConfigurations": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/_2.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/_2.lockType",
- "nullable": true,
- "metadata": {
- "description": "Optional. Specify the type of lock."
- }
- },
- "roleAssignments": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/_2.roleAssignmentType"
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. Array of role assignments to create."
- }
- },
- "tags": {
- "type": "object",
- "nullable": true,
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2024-07-01#properties/tags"
- },
- "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.6.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.6.0"
- }
- }
- },
- "secretsOutputType": {
- "type": "object",
- "properties": {},
- "additionalProperties": {
- "$ref": "#/definitions/_1.secretSetOutputType",
- "metadata": {
- "description": "An exported secret's references."
- }
- },
- "metadata": {
- "description": "A map of the exported secrets",
- "__bicep_imported_from!": {
- "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0"
- }
- }
- }
- },
- "parameters": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "Required. The name of Cognitive Services account."
- }
- },
- "kind": {
- "type": "string",
- "allowedValues": [
- "AIServices",
- "AnomalyDetector",
- "CognitiveServices",
- "ComputerVision",
- "ContentModerator",
- "ContentSafety",
- "ConversationalLanguageUnderstanding",
- "CustomVision.Prediction",
- "CustomVision.Training",
- "Face",
- "FormRecognizer",
- "HealthInsights",
- "ImmersiveReader",
- "Internal.AllInOne",
- "LUIS",
- "LUIS.Authoring",
- "LanguageAuthoring",
- "MetricsAdvisor",
- "OpenAI",
- "Personalizer",
- "QnAMaker.v2",
- "SpeechServices",
- "TextAnalytics",
- "TextTranslation"
- ],
- "metadata": {
- "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region."
- }
- },
- "sku": {
- "type": "string",
- "defaultValue": "S0",
- "allowedValues": [
- "C2",
- "C3",
- "C4",
- "F0",
- "F1",
- "S",
- "S0",
- "S1",
- "S10",
- "S2",
- "S3",
- "S4",
- "S5",
- "S6",
- "S7",
- "S8",
- "S9",
- "DC0"
- ],
- "metadata": {
- "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region."
- }
- },
- "location": {
- "type": "string",
- "defaultValue": "[resourceGroup().location]",
- "metadata": {
- "description": "Optional. Location for all Resources."
- }
- },
- "diagnosticSettings": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/diagnosticSettingFullType"
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. The diagnostic settings of the service."
- }
- },
- "publicNetworkAccess": {
- "type": "string",
- "nullable": true,
- "allowedValues": [
- "Enabled",
- "Disabled"
- ],
- "metadata": {
- "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set."
- }
- },
- "customSubDomainName": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set."
- }
- },
- "networkAcls": {
- "type": "object",
- "nullable": true,
- "metadata": {
- "description": "Optional. A collection of rules governing the accessibility from specific network locations."
- }
- },
- "networkInjections": {
- "$ref": "#/definitions/networkInjectionType",
- "nullable": true,
- "metadata": {
- "description": "Optional. Specifies in AI Foundry where virtual network injection occurs to secure scenarios like Agents entirely within a private network."
- }
- },
- "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."
- }
- },
- "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."
- }
- },
- "tags": {
- "type": "object",
- "nullable": true,
- "metadata": {
- "description": "Optional. Tags of the resource."
- }
- },
- "allowedFqdnList": {
- "type": "array",
- "nullable": true,
- "metadata": {
- "description": "Optional. List of allowed FQDN."
- }
- },
- "apiProperties": {
- "type": "object",
- "nullable": true,
- "metadata": {
- "description": "Optional. The API properties for special APIs."
- }
- },
- "disableLocalAuth": {
- "type": "bool",
- "defaultValue": true,
- "metadata": {
- "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons."
- }
- },
- "customerManagedKey": {
- "$ref": "#/definitions/customerManagedKeyType",
- "nullable": true,
- "metadata": {
- "description": "Optional. The customer managed key definition."
- }
- },
- "dynamicThrottlingEnabled": {
- "type": "bool",
- "defaultValue": false,
- "metadata": {
- "description": "Optional. The flag to enable dynamic throttling."
- }
- },
- "migrationToken": {
- "type": "securestring",
- "nullable": true,
- "metadata": {
- "description": "Optional. Resource migration token."
- }
- },
- "restore": {
- "type": "bool",
- "defaultValue": false,
- "metadata": {
- "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists."
- }
- },
- "restrictOutboundNetworkAccess": {
- "type": "bool",
- "defaultValue": true,
- "metadata": {
- "description": "Optional. Restrict outbound network access."
- }
- },
- "userOwnedStorage": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.CognitiveServices/accounts@2025-04-01-preview#properties/properties/properties/userOwnedStorage"
- },
- "description": "Optional. The storage accounts for this resource."
- },
- "nullable": true
- },
- "managedIdentities": {
- "$ref": "#/definitions/managedIdentityAllType",
- "nullable": true,
- "metadata": {
- "description": "Optional. The managed identity definition for this resource."
- }
- },
- "enableTelemetry": {
- "type": "bool",
- "defaultValue": true,
- "metadata": {
- "description": "Optional. Enable/Disable usage telemetry for module."
- }
- },
- "deployments": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/deploymentType"
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. Array of deployments about cognitive service accounts to create."
- }
- },
- "secretsExportConfiguration": {
- "$ref": "#/definitions/secretsExportConfigurationType",
- "nullable": true,
- "metadata": {
- "description": "Optional. Key vault reference and secret settings for the module's secrets export."
- }
- },
- "allowProjectManagement": {
- "type": "bool",
- "nullable": true,
- "metadata": {
- "description": "Optional. Enable/Disable project management feature for AI Foundry."
- }
- },
- "commitmentPlans": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/commitmentPlanType"
- },
- "nullable": true,
- "metadata": {
- "description": "Optional. Commitment plans to deploy for the cognitive services account."
- }
- }
- },
- "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)))))]"
- }
- ],
- "enableReferencedModulesTelemetry": false,
- "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]",
- "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]",
- "builtInRoleNames": {
- "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]",
- "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]",
- "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]",
- "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]",
- "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]",
- "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]",
- "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]",
- "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]",
- "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]",
- "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]",
- "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]",
- "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]",
- "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]",
- "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]",
- "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]",
- "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]",
- "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]",
- "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]",
- "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]",
- "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]",
- "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]",
- "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]",
- "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]",
- "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]",
- "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]",
- "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')]"
- },
- "isHSMManagedCMK": "[equals(tryGet(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), ''), '/'), 7), 'managedHSMs')]"
- },
- "resources": {
- "cMKKeyVault::cMKKey": {
- "condition": "[and(and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))), and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK'))))]",
- "existing": true,
- "type": "Microsoft.KeyVault/vaults/keys",
- "apiVersion": "2025-05-01",
- "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]",
- "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]",
- "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]"
- },
- "avmTelemetry": {
- "condition": "[parameters('enableTelemetry')]",
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2024-03-01",
- "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('0.14.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]",
- "properties": {
- "mode": "Incremental",
- "template": {
- "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
- "contentVersion": "1.0.0.0",
- "resources": [],
- "outputs": {
- "telemetry": {
- "type": "String",
- "value": "For more information, see https://aka.ms/avm/TelemetryInfo"
- }
- }
- }
- }
- },
- "cMKKeyVault": {
- "condition": "[and(not(empty(parameters('customerManagedKey'))), not(variables('isHSMManagedCMK')))]",
- "existing": true,
- "type": "Microsoft.KeyVault/vaults",
- "apiVersion": "2025-05-01",
- "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]",
- "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]",
- "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]"
- },
- "cMKUserAssignedIdentity": {
- "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]",
- "existing": true,
- "type": "Microsoft.ManagedIdentity/userAssignedIdentities",
- "apiVersion": "2025-01-31-preview",
- "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]",
- "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]",
- "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]"
- },
- "cognitiveService": {
- "type": "Microsoft.CognitiveServices/accounts",
- "apiVersion": "2025-06-01",
- "name": "[parameters('name')]",
- "kind": "[parameters('kind')]",
- "identity": "[variables('identity')]",
- "location": "[parameters('location')]",
- "tags": "[parameters('tags')]",
- "sku": {
- "name": "[parameters('sku')]"
- },
- "properties": {
- "allowProjectManagement": "[parameters('allowProjectManagement')]",
- "customSubDomainName": "[parameters('customSubDomainName')]",
- "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]",
- "networkInjections": "[if(not(empty(parameters('networkInjections'))), createArray(createObject('scenario', tryGet(parameters('networkInjections'), 'scenario'), 'subnetArmId', tryGet(parameters('networkInjections'), 'subnetResourceId'), 'useMicrosoftManagedNetwork', coalesce(tryGet(parameters('networkInjections'), 'useMicrosoftManagedNetwork'), false()))), null())]",
- "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]",
- "allowedFqdnList": "[parameters('allowedFqdnList')]",
- "apiProperties": "[parameters('apiProperties')]",
- "disableLocalAuth": "[parameters('disableLocalAuth')]",
- "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', if(not(variables('isHSMManagedCMK')), reference('cMKKeyVault').vaultUri, format('https://{0}.managedhsm.azure.net/', last(split(parameters('customerManagedKey').keyVaultResourceId, '/')))), 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(not(variables('isHSMManagedCMK')), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')), fail('Managed HSM CMK encryption requires specifying the ''keyVersion''.'))))), null())]",
- "migrationToken": "[parameters('migrationToken')]",
- "restore": "[parameters('restore')]",
- "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]",
- "userOwnedStorage": "[if(not(empty(parameters('userOwnedStorage'))), parameters('userOwnedStorage'), null())]",
- "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]"
- },
- "dependsOn": [
- "cMKKeyVault",
- "cMKKeyVault::cMKKey",
- "cMKUserAssignedIdentity"
- ]
- },
- "cognitiveService_deployments": {
- "copy": {
- "name": "cognitiveService_deployments",
- "count": "[length(coalesce(parameters('deployments'), createArray()))]",
- "mode": "serial",
- "batchSize": 1
- },
- "type": "Microsoft.CognitiveServices/accounts/deployments",
- "apiVersion": "2025-06-01",
- "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]",
- "properties": {
- "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]",
- "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]",
- "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]"
- },
- "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]",
- "dependsOn": [
- "cognitiveService"
- ]
- },
- "cognitiveService_lock": {
- "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]",
- "type": "Microsoft.Authorization/locks",
- "apiVersion": "2020-05-01",
- "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]",
- "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]",
- "properties": {
- "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]",
- "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]"
- },
- "dependsOn": [
- "cognitiveService"
- ]
- },
- "cognitiveService_commitmentPlans": {
- "copy": {
- "name": "cognitiveService_commitmentPlans",
- "count": "[length(coalesce(parameters('commitmentPlans'), createArray()))]"
- },
- "type": "Microsoft.CognitiveServices/accounts/commitmentPlans",
- "apiVersion": "2025-06-01",
- "name": "[format('{0}/{1}', parameters('name'), format('{0}-{1}', coalesce(parameters('commitmentPlans'), createArray())[copyIndex()].hostingModel, coalesce(parameters('commitmentPlans'), createArray())[copyIndex()].planType))]",
- "properties": "[coalesce(parameters('commitmentPlans'), createArray())[copyIndex()]]",
- "dependsOn": [
- "cognitiveService"
- ]
- },
- "cognitiveService_diagnosticSettings": {
- "copy": {
- "name": "cognitiveService_diagnosticSettings",
- "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]"
- },
- "type": "Microsoft.Insights/diagnosticSettings",
- "apiVersion": "2021-05-01-preview",
- "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]",
- "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]",
- "properties": {
- "copy": [
- {
- "name": "metrics",
- "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]",
- "input": {
- "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]",
- "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]",
- "timeGrain": null
- }
- },
- {
- "name": "logs",
- "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]",
- "input": {
- "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]",
- "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]",
- "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]"
- }
- }
- ],
- "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]",
- "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]",
- "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]",
- "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]",
- "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]",
- "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]"
- },
- "dependsOn": [
- "cognitiveService"
- ]
- },
- "cognitiveService_roleAssignments": {
- "copy": {
- "name": "cognitiveService_roleAssignments",
- "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]"
- },
- "type": "Microsoft.Authorization/roleAssignments",
- "apiVersion": "2022-04-01",
- "scope": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]",
- "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]",
- "properties": {
- "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]",
- "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]",
- "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]",
- "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]",
- "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]",
- "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]",
- "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]"
- },
- "dependsOn": [
- "cognitiveService"
- ]
- },
- "cognitiveService_privateEndpoints": {
- "copy": {
- "name": "cognitiveService_privateEndpoints",
- "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]"
- },
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-01",
- "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]",
- "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]",
- "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[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.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]"
- },
- "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]",
- "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]",
- "subnetResourceId": {
- "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]"
- },
- "enableTelemetry": {
- "value": "[variables('enableReferencedModulesTelemetry')]"
- },
- "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.38.5.1644",
- "templateHash": "16604612898799598358"
- },
- "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,
- "description": "The type of a private dns zone group."
- }
- },
- "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."
- }
- },
- "notes": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Specify the notes of the 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.6.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": {
- "description": "The type of a private DNS zone group configuration.",
- "__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.6.1"
- }
- }
- }
- },
- "parameters": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "Required. Name of the private endpoint resource to create."
- }
- },
- "subnetResourceId": {
- "type": "string",
- "metadata": {
- "description": "Required. Resource ID of the subnet where the endpoint needs to be created."
- }
- },
- "applicationSecurityGroupResourceIds": {
- "type": "array",
- "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."
- }
- },
- "ipConfigurations": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations"
- },
- "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints."
- },
- "nullable": true
- },
- "privateDnsZoneGroup": {
- "$ref": "#/definitions/privateDnsZoneGroupType",
- "nullable": true,
- "metadata": {
- "description": "Optional. The private DNS zone group to configure for the private endpoint."
- }
- },
- "location": {
- "type": "string",
- "defaultValue": "[resourceGroup().location]",
- "metadata": {
- "description": "Optional. Location for all Resources."
- }
- },
- "lock": {
- "$ref": "#/definitions/lockType",
- "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."
- }
- },
- "tags": {
- "type": "object",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags"
- },
- "description": "Optional. Tags to be applied on all resources/resource groups in this deployment."
- },
- "nullable": true
- },
- "customDnsConfigs": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs"
- },
- "description": "Optional. Custom DNS configurations."
- },
- "nullable": true
- },
- "manualPrivateLinkServiceConnections": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections"
- },
- "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."
- },
- "nullable": true
- },
- "privateLinkServiceConnections": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections"
- },
- "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty."
- },
- "nullable": true
- },
- "enableTelemetry": {
- "type": "bool",
- "defaultValue": true,
- "metadata": {
- "description": "Optional. Enable/Disable usage telemetry for module."
- }
- }
- },
- "variables": {
- "copy": [
- {
- "name": "formattedRoleAssignments",
- "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]",
- "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]"
- }
- ],
- "builtInRoleNames": {
- "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
- "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]",
- "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]",
- "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]",
- "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]",
- "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]",
- "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
- "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]",
- "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
- "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]"
- }
- },
- "resources": {
- "avmTelemetry": {
- "condition": "[parameters('enableTelemetry')]",
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-01",
- "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]",
- "properties": {
- "mode": "Incremental",
- "template": {
- "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
- "contentVersion": "1.0.0.0",
- "resources": [],
- "outputs": {
- "telemetry": {
- "type": "String",
- "value": "For more information, see https://aka.ms/avm/TelemetryInfo"
- }
- }
- }
- }
- },
- "privateEndpoint": {
- "type": "Microsoft.Network/privateEndpoints",
- "apiVersion": "2024-10-01",
- "name": "[parameters('name')]",
- "location": "[parameters('location')]",
- "tags": "[parameters('tags')]",
- "properties": {
- "copy": [
- {
- "name": "applicationSecurityGroups",
- "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]",
- "input": {
- "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]"
- }
- }
- ],
- "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]",
- "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]",
- "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]",
- "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]",
- "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]",
- "subnet": {
- "id": "[parameters('subnetResourceId')]"
- }
- }
- },
- "privateEndpoint_lock": {
- "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]",
- "type": "Microsoft.Authorization/locks",
- "apiVersion": "2020-05-01",
- "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]",
- "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]",
- "properties": {
- "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]",
- "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]"
- },
- "dependsOn": [
- "privateEndpoint"
- ]
- },
- "privateEndpoint_roleAssignments": {
- "copy": {
- "name": "privateEndpoint_roleAssignments",
- "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]"
- },
- "type": "Microsoft.Authorization/roleAssignments",
- "apiVersion": "2022-04-01",
- "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]",
- "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]",
- "properties": {
- "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]",
- "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]",
- "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]",
- "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]",
- "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]",
- "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]",
- "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]"
- },
- "dependsOn": [
- "privateEndpoint"
- ]
- },
- "privateEndpoint_privateDnsZoneGroup": {
- "condition": "[not(empty(parameters('privateDnsZoneGroup')))]",
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-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.38.5.1644",
- "templateHash": "24141742673128945"
- },
- "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,
- "description": "The type of a private DNS zone group configuration."
- }
- }
- },
- "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."
- }
- }
- },
- "resources": {
- "privateEndpoint": {
- "existing": true,
- "type": "Microsoft.Network/privateEndpoints",
- "apiVersion": "2024-10-01",
- "name": "[parameters('privateEndpointName')]"
- },
- "privateDnsZoneGroup": {
- "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
- "apiVersion": "2024-10-01",
- "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]",
- "properties": {
- "copy": [
- {
- "name": "privateDnsZoneConfigs",
- "count": "[length(parameters('privateDnsZoneConfigs'))]",
- "input": {
- "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]",
- "properties": {
- "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]"
- }
- }
- }
- ]
- }
- }
- },
- "outputs": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "The name of the private endpoint DNS zone group."
- },
- "value": "[parameters('name')]"
- },
- "resourceId": {
- "type": "string",
- "metadata": {
- "description": "The resource ID of the private endpoint DNS zone group."
- },
- "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]"
- },
- "resourceGroupName": {
- "type": "string",
- "metadata": {
- "description": "The resource group the private endpoint DNS zone group was deployed into."
- },
- "value": "[resourceGroup().name]"
- }
- }
- }
- },
- "dependsOn": [
- "privateEndpoint"
- ]
- }
- },
- "outputs": {
- "resourceGroupName": {
- "type": "string",
- "metadata": {
- "description": "The resource group the private endpoint was deployed into."
- },
- "value": "[resourceGroup().name]"
- },
- "resourceId": {
- "type": "string",
- "metadata": {
- "description": "The resource ID of the private endpoint."
- },
- "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]"
- },
- "name": {
- "type": "string",
- "metadata": {
- "description": "The name of the private endpoint."
- },
- "value": "[parameters('name')]"
- },
- "location": {
- "type": "string",
- "metadata": {
- "description": "The location the resource was deployed into."
- },
- "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]"
- },
- "customDnsConfigs": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs",
- "output": true
- },
- "description": "The custom DNS configurations of the private endpoint."
- },
- "value": "[reference('privateEndpoint').customDnsConfigs]"
- },
- "networkInterfaceResourceIds": {
- "type": "array",
- "items": {
- "type": "string"
- },
- "metadata": {
- "description": "The resource IDs of the network interfaces associated with the private endpoint."
- },
- "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]"
- },
- "groupId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "The group Id for the private endpoint Group."
- },
- "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": [
- "cognitiveService"
- ]
- },
- "secretsExport": {
- "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]",
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-01",
- "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]",
- "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]",
- "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]",
- "properties": {
- "expressionEvaluationOptions": {
- "scope": "inner"
- },
- "mode": "Incremental",
- "parameters": {
- "keyVaultName": {
- "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]"
- },
- "secretsToSet": {
- "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-06-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-06-01').key2)), createArray()))]"
- }
- },
- "template": {
- "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
- "languageVersion": "2.0",
- "contentVersion": "1.0.0.0",
- "metadata": {
- "_generator": {
- "name": "bicep",
- "version": "0.41.2.15936",
- "templateHash": "13968722110082077308"
- }
- },
- "definitions": {
- "secretSetOutputType": {
- "type": "object",
- "properties": {
- "secretResourceId": {
- "type": "string",
- "metadata": {
- "description": "The resourceId of the exported secret."
- }
- },
- "secretUri": {
- "type": "string",
- "metadata": {
- "description": "The secret URI of the exported secret."
- }
- },
- "secretUriWithVersion": {
- "type": "string",
- "metadata": {
- "description": "The secret URI with version of the exported secret."
- }
- }
- },
- "metadata": {
- "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.",
- "__bicep_imported_from!": {
- "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1"
- }
- }
- },
- "secretToSetType": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "Required. The name of the secret to set."
- }
- },
- "value": {
- "type": "securestring",
- "metadata": {
- "description": "Required. The value of the secret to set."
- }
- }
- },
- "metadata": {
- "description": "An AVM-aligned type for the secret to set via the secrets export feature.",
- "__bicep_imported_from!": {
- "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1"
- }
- }
- }
- },
- "parameters": {
- "keyVaultName": {
- "type": "string",
- "metadata": {
- "description": "Required. The name of the Key Vault to set the ecrets in."
- }
- },
- "secretsToSet": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/secretToSetType"
- },
- "metadata": {
- "description": "Required. The secrets to set in the Key Vault."
- }
- }
- },
- "resources": {
- "keyVault": {
- "existing": true,
- "type": "Microsoft.KeyVault/vaults",
- "apiVersion": "2025-05-01",
- "name": "[parameters('keyVaultName')]"
- },
- "secrets": {
- "copy": {
- "name": "secrets",
- "count": "[length(parameters('secretsToSet'))]"
- },
- "type": "Microsoft.KeyVault/vaults/secrets",
- "apiVersion": "2025-05-01",
- "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]",
- "properties": {
- "value": "[parameters('secretsToSet')[copyIndex()].value]"
- }
- }
- },
- "outputs": {
- "secretsSet": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/secretSetOutputType"
- },
- "metadata": {
- "description": "The references to the secrets exported to the provided Key Vault."
- },
- "copy": {
- "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]",
- "input": {
- "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]",
- "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]",
- "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]"
- }
- }
- }
- }
- }
- },
- "dependsOn": [
- "cognitiveService"
- ]
- }
- },
- "outputs": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "The name of the cognitive services account."
- },
- "value": "[parameters('name')]"
- },
- "resourceId": {
- "type": "string",
- "metadata": {
- "description": "The resource ID of the cognitive services account."
- },
- "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]"
- },
- "resourceGroupName": {
- "type": "string",
- "metadata": {
- "description": "The resource group the cognitive services account was deployed into."
- },
- "value": "[resourceGroup().name]"
- },
- "endpoint": {
- "type": "string",
- "metadata": {
- "description": "The service endpoint of the cognitive services account."
- },
- "value": "[reference('cognitiveService').endpoint]"
- },
- "endpoints": {
- "$ref": "#/definitions/endpointType",
- "metadata": {
- "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind."
- },
- "value": "[reference('cognitiveService').endpoints]"
- },
- "systemAssignedMIPrincipalId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "The principal ID of the system assigned identity."
- },
- "value": "[tryGet(tryGet(reference('cognitiveService', '2025-06-01', 'full'), 'identity'), 'principalId')]"
- },
- "location": {
- "type": "string",
- "metadata": {
- "description": "The location the resource was deployed into."
- },
- "value": "[reference('cognitiveService', '2025-06-01', 'full').location]"
- },
- "exportedSecrets": {
- "$ref": "#/definitions/secretsOutputType",
- "metadata": {
- "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name."
- },
- "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]"
- },
- "privateEndpoints": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/privateEndpointOutputType"
- },
- "metadata": {
- "description": "The private endpoints of the congitive services account."
- },
- "copy": {
- "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]",
- "input": {
- "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]",
- "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]",
- "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]",
- "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]",
- "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]"
- }
- }
- },
- "primaryKey": {
- "type": "securestring",
- "nullable": true,
- "metadata": {
- "description": "The primary access key."
- },
- "value": "[if(not(parameters('disableLocalAuth')), listKeys('cognitiveService', '2025-06-01').key1, null())]"
- },
- "secondaryKey": {
- "type": "securestring",
- "nullable": true,
- "metadata": {
- "description": "The secondary access key."
- },
- "value": "[if(not(parameters('disableLocalAuth')), listKeys('cognitiveService', '2025-06-01').key2, null())]"
- }
- }
- }
- },
- "dependsOn": [
- "avmContainerApp",
- "avmContainerApp_Workflow",
- "avmManagedIdentity"
- ]
- },
- "contentUnderstandingPrivateEndpoint": {
- "condition": "[parameters('enablePrivateNetworking')]",
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-01",
- "name": "[take(format('avm.res.network.private-endpoint.aicu-{0}', variables('solutionSuffix')), 64)]",
- "properties": {
- "expressionEvaluationOptions": {
- "scope": "inner"
- },
- "mode": "Incremental",
- "parameters": {
- "name": {
- "value": "[format('pep-aicu-{0}', variables('solutionSuffix'))]"
- },
- "location": {
- "value": "[parameters('location')]"
- },
- "tags": {
- "value": "[parameters('tags')]"
- },
- "customNetworkInterfaceName": {
- "value": "[format('nic-aicu-{0}', variables('solutionSuffix'))]"
- },
- "privateLinkServiceConnections": {
- "value": [
- {
- "name": "[format('pep-aicu-{0}-cognitiveservices-connection', variables('solutionSuffix'))]",
- "properties": {
- "privateLinkServiceId": "[reference('avmAiServices_cu').outputs.resourceId.value]",
- "groupIds": [
- "account"
- ]
- }
- }
- ]
- },
- "privateDnsZoneGroup": {
- "value": {
- "privateDnsZoneGroupConfigs": [
- {
- "name": "aicu-dns-zone-cognitiveservices",
- "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value]"
- },
- {
- "name": "ai-services-dns-zone-aiservices",
- "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)).outputs.resourceId.value]"
- },
- {
- "name": "aicu-dns-zone-contentunderstanding",
- "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)).outputs.resourceId.value]"
- }
- ]
- }
- },
- "subnetResourceId": {
- "value": "[reference('virtualNetwork').outputs.backendSubnetResourceId.value]"
- }
- },
- "template": {
- "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
- "languageVersion": "2.0",
- "contentVersion": "1.0.0.0",
- "metadata": {
- "_generator": {
- "name": "bicep",
- "version": "0.41.2.15936",
- "templateHash": "18436885663402767850"
- },
- "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,
- "description": "The type of a private dns zone group."
- }
- },
- "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."
- }
- },
- "notes": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. Specify the notes of the 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.7.0"
- }
- }
- },
- "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": {
- "description": "The type of a private DNS zone group configuration.",
- "__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.7.0"
- }
- }
- }
- },
- "parameters": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "Required. Name of the private endpoint resource to create."
- }
- },
- "subnetResourceId": {
- "type": "string",
- "metadata": {
- "description": "Required. Resource ID of the subnet where the endpoint needs to be created."
- }
- },
- "applicationSecurityGroupResourceIds": {
- "type": "array",
- "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."
- }
- },
- "ipConfigurations": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipConfigurations"
- },
- "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints."
- },
- "nullable": true
- },
- "ipVersionType": {
- "type": "string",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/ipVersionType"
- },
- "description": "Optional. Specifies the IP version type for the private IPs of the private endpoint. If not defined, this defaults to IPv4."
- },
- "defaultValue": "IPv4"
- },
- "privateDnsZoneGroup": {
- "$ref": "#/definitions/privateDnsZoneGroupType",
- "nullable": true,
- "metadata": {
- "description": "Optional. The private DNS zone group to configure for the private endpoint."
- }
- },
- "location": {
- "type": "string",
- "defaultValue": "[resourceGroup().location]",
- "metadata": {
- "description": "Optional. Location for all Resources."
- }
- },
- "lock": {
- "$ref": "#/definitions/lockType",
- "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."
- }
- },
- "tags": {
- "type": "object",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/tags"
- },
- "description": "Optional. Tags to be applied on all resources/resource groups in this deployment."
- },
- "nullable": true
- },
- "customDnsConfigs": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs"
- },
- "description": "Optional. Custom DNS configurations."
- },
- "nullable": true
- },
- "manualPrivateLinkServiceConnections": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/manualPrivateLinkServiceConnections"
- },
- "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."
- },
- "nullable": true
- },
- "privateLinkServiceConnections": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/privateLinkServiceConnections"
- },
- "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty."
- },
- "nullable": true
- },
- "enableTelemetry": {
- "type": "bool",
- "defaultValue": true,
- "metadata": {
- "description": "Optional. Enable/Disable usage telemetry for module."
- }
- }
- },
- "variables": {
- "copy": [
- {
- "name": "formattedRoleAssignments",
- "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]",
- "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]"
- }
- ],
- "builtInRoleNames": {
- "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
- "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]",
- "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]",
- "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]",
- "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]",
- "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]",
- "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
- "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]",
- "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
- "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]"
- }
- },
- "resources": {
- "avmTelemetry": {
- "condition": "[parameters('enableTelemetry')]",
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-01",
- "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]",
- "properties": {
- "mode": "Incremental",
- "template": {
- "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
- "contentVersion": "1.0.0.0",
- "resources": [],
- "outputs": {
- "telemetry": {
- "type": "String",
- "value": "For more information, see https://aka.ms/avm/TelemetryInfo"
- }
- }
- }
- }
- },
- "privateEndpoint": {
- "type": "Microsoft.Network/privateEndpoints",
- "apiVersion": "2025-05-01",
- "name": "[parameters('name')]",
- "location": "[parameters('location')]",
- "tags": "[parameters('tags')]",
- "properties": {
- "copy": [
- {
- "name": "applicationSecurityGroups",
- "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]",
- "input": {
- "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]"
- }
- }
- ],
- "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]",
- "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]",
- "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]",
- "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]",
- "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]",
- "subnet": {
- "id": "[parameters('subnetResourceId')]"
- },
- "ipVersionType": "[parameters('ipVersionType')]"
- }
- },
- "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": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]",
- "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]",
- "properties": {
- "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]",
- "notes": "[coalesce(tryGet(parameters('lock'), 'notes'), if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.'))]"
- },
- "dependsOn": [
- "privateEndpoint"
- ]
- },
- "privateEndpoint_roleAssignments": {
- "copy": {
- "name": "privateEndpoint_roleAssignments",
- "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]"
- },
- "type": "Microsoft.Authorization/roleAssignments",
- "apiVersion": "2022-04-01",
- "scope": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]",
- "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]",
- "properties": {
- "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]",
- "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]",
- "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]",
- "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]",
- "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]",
- "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]",
- "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]"
- },
- "dependsOn": [
- "privateEndpoint"
- ]
- },
- "privateEndpoint_privateDnsZoneGroup": {
- "condition": "[not(empty(parameters('privateDnsZoneGroup')))]",
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-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.41.2.15936",
- "templateHash": "9935179114830442414"
- },
- "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,
- "description": "The type of a private DNS zone group configuration."
- }
- }
- },
- "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."
- }
- }
- },
- "resources": {
- "privateEndpoint": {
- "existing": true,
- "type": "Microsoft.Network/privateEndpoints",
- "apiVersion": "2025-05-01",
- "name": "[parameters('privateEndpointName')]"
- },
- "privateDnsZoneGroup": {
- "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
- "apiVersion": "2025-05-01",
- "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]",
- "properties": {
- "copy": [
- {
- "name": "privateDnsZoneConfigs",
- "count": "[length(parameters('privateDnsZoneConfigs'))]",
- "input": {
- "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]",
- "properties": {
- "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]"
- }
- }
- }
- ]
- }
- }
- },
- "outputs": {
- "name": {
- "type": "string",
- "metadata": {
- "description": "The name of the private endpoint DNS zone group."
- },
- "value": "[parameters('name')]"
- },
- "resourceId": {
- "type": "string",
- "metadata": {
- "description": "The resource ID of the private endpoint DNS zone group."
- },
- "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]"
- },
- "resourceGroupName": {
- "type": "string",
- "metadata": {
- "description": "The resource group the private endpoint DNS zone group was deployed into."
- },
- "value": "[resourceGroup().name]"
- }
- }
- }
- },
- "dependsOn": [
- "privateEndpoint"
- ]
- }
- },
- "outputs": {
- "resourceGroupName": {
- "type": "string",
- "metadata": {
- "description": "The resource group the private endpoint was deployed into."
- },
- "value": "[resourceGroup().name]"
- },
- "resourceId": {
- "type": "string",
- "metadata": {
- "description": "The resource ID of the private endpoint."
- },
- "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]"
- },
- "name": {
- "type": "string",
- "metadata": {
- "description": "The name of the private endpoint."
- },
- "value": "[parameters('name')]"
- },
- "location": {
- "type": "string",
- "metadata": {
- "description": "The location the resource was deployed into."
- },
- "value": "[reference('privateEndpoint', '2025-05-01', 'full').location]"
- },
- "customDnsConfigs": {
- "type": "array",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.Network/privateEndpoints@2025-05-01#properties/properties/properties/customDnsConfigs",
- "output": true
- },
- "description": "The custom DNS configurations of the private endpoint."
- },
- "value": "[reference('privateEndpoint').customDnsConfigs]"
- },
- "networkInterfaceResourceIds": {
- "type": "array",
- "items": {
- "type": "string"
- },
- "metadata": {
- "description": "The resource IDs of the network interfaces associated with the private endpoint."
- },
- "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]"
- },
- "groupId": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "The group Id for the private endpoint Group."
- },
- "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": [
- "avmAiServices_cu",
- "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]",
- "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]",
- "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]",
- "virtualNetwork"
- ]
- },
- "avmContainerAppEnv": {
- "type": "Microsoft.Resources/deployments",
- "apiVersion": "2025-04-01",
- "name": "[take(format('avm.res.app.managed-environment.{0}', variables('solutionSuffix')), 64)]",
- "properties": {
- "expressionEvaluationOptions": {
- "scope": "inner"
- },
- "mode": "Incremental",
- "parameters": {
- "name": {
- "value": "[format('cae-{0}', variables('solutionSuffix'))]"
- },
- "location": {
- "value": "[parameters('location')]"
- },
- "tags": {
- "value": "[shallowMerge(createArray(resourceGroup().tags, parameters('tags')))]"
- },
- "managedIdentities": {
- "value": {
- "systemAssigned": true
- }
- },
- "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsWorkspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', null()))]",
- "workloadProfiles": {
- "value": [
- {
- "name": "Consumption",
- "workloadProfileType": "Consumption"
- }
- ]
- },
- "enableTelemetry": {
- "value": "[parameters('enableTelemetry')]"
- },
- "publicNetworkAccess": {
- "value": "Enabled"
- },
- "platformReservedCidr": {
- "value": "172.17.17.0/24"
- },
- "platformReservedDnsIP": {
- "value": "172.17.17.17"
- },
- "zoneRedundant": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]",
- "infrastructureSubnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.containersSubnetResourceId.value), createObject('value', null()))]"
- },
- "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.42.1.51946",
- "templateHash": "11924518395502120940"
- },
- "name": "App ManagedEnvironments",
- "description": "This module deploys an App Managed Environment (also known as a Container App Environment)."
- },
- "definitions": {
- "certificateType": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The name of the certificate."
- }
- },
- "certificateType": {
- "type": "string",
- "allowedValues": [
- "ImagePullTrustedCA",
- "ServerSSLCertificate"
- ],
- "nullable": true,
- "metadata": {
- "description": "Optional. The type of the certificate."
- }
- },
- "certificateValue": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The value of the certificate. PFX or PEM blob."
- }
- },
- "certificatePassword": {
- "type": "securestring",
- "nullable": true,
- "metadata": {
- "description": "Optional. The password of the certificate."
- }
- },
- "certificateKeyVaultProperties": {
- "$ref": "#/definitions/certificateKeyVaultPropertiesType",
- "nullable": true,
- "metadata": {
- "description": "Optional. A key vault reference."
- }
- },
- "location": {
- "type": "string",
- "nullable": true,
- "metadata": {
- "description": "Optional. The location for the resource."
- }
- },
- "tags": {
- "type": "object",
- "metadata": {
- "__bicep_resource_derived_type!": {
- "source": "Microsoft.App/managedEnvironments/certificates@2025-10-02-preview#properties/tags"
- },
- "description": "Optional. Tags of the resource."
- },
- "nullable": true
- }
- },
- "metadata": {
- "__bicep_export!": true,
- "description": "The type for a certificate."
- }
- },
- "storageType": {
- "type": "object",
- "properties": {
- "accessMode": {
- "type": "string",
- "allowedValues": [
- "ReadOnly",
- "ReadWrite"
- ],
- "metadata": {
- "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"."
- }
- },
- "kind": {
- "type": "string",
- "allowedValues": [
- "NFS",
- "SMB"
- ],
- "metadata": {
- "description": "Required. Type of storage: \"SMB\" or \"NFS\"."
- }
- },
- "storageAccountName": {
- "type": "string",
- "metadata": {
- "description": "Required. Storage account name."
- }
- },
- "name": {
- "type": "string",
- "metadata": {
- "description": "Required. File share name."
- }
- }
- },
- "metadata": {
- "__bicep_export!": true,
- "description": "The type of the storage."
- }
- },
- "appLogsConfigurationType": {
- "type": "object",
- "discriminator": {
- "propertyName": "destination",
- "mapping": {
- "azure-monitor": {
- "$ref": "#/definitions/appLogsConfigurationMonitorType"
- },
- "log-analytics": {
- "$ref": "#/definitions/appLogsConfigurationLawType"
- }
- }
- },
- "metadata": {
- "__bicep_export!": true,
- "description": "The type for the App Logs Configuration."
- }
- },
- "appLogsConfigurationMonitorType": {
- "type": "object",
- "properties": {
- "destination": {
- "type": "string",
- "allowedValues": [
- "azure-monitor"
- ],
- "metadata": {
- "description": "Required. The destination of the logs."
- }
- }
- },
- "metadata": {
- "description": "The type for the App Logs Configuration if using azure-monitor."
- }
- },
- "appLogsConfigurationLawType": {
- "type": "object",
- "properties": {
- "destination": {
- "type": "string",
- "allowedValues": [
- "log-analytics"
- ],
- "metadata": {
- "description": "Required. The destination of the logs."
- }
- },
- "logAnalyticsWorkspaceResourceId": {
- "type": "string",
- "metadata": {
- "description": "Required. Existing Log Analytics Workspace resource ID."
- }
- }
- },
- "metadata": {
- "description": "The type for the App Logs Configuration if using log-analytics."
- }
- },
- "certificateKeyVaultPropertiesType": {
- "type": "object",
- "properties": {
- "identityResourceId": {
- "type": "string",
- "metadata": {
- "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault."
- }
- },
- "keyVaultUrl": {
- "type": "string",
- "metadata": {
- "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain."
- }
- }
- },
- "metadata": {
- "description": "The type for the certificate's key vault properties.",
- "__bicep_imported_from!": {
- "sourceTemplate": "certificate/main.bicep"
- }
- }
- },
- "lockType": {
+ "lockType": {
"type": "object",
"properties": {
"name": {
@@ -59999,7 +56802,7 @@
},
{
"name": "APP_CONTENT_UNDERSTANDING_ENDPOINT",
- "value": "[reference('avmAiServices_cu').outputs.endpoint.value]"
+ "value": "[reference('avmAiServices').outputs.endpoint.value]"
},
{
"name": "APP_COSMOS_CONTAINER_PROCESS",
@@ -62348,7 +59151,6 @@
},
"dependsOn": [
"avmAiServices",
- "avmAiServices_cu",
"avmContainerApp",
"avmContainerApp_API",
"avmContainerApp_Web",
@@ -66229,8 +63031,7 @@
"avmAppConfig",
"avmContainerAppEnv",
"avmContainerRegistryReader",
- "cognitiveServicePrivateEndpoint",
- "contentUnderstandingPrivateEndpoint"
+ "cognitiveServicePrivateEndpoint"
]
},
"avmContainerApp_API_update": {
@@ -69637,9 +66438,9 @@
"CONTENT_UNDERSTANDING_ACCOUNT_NAME": {
"type": "string",
"metadata": {
- "description": "The name of the Content Understanding AI Services account."
+ "description": "The name of the AI Services account that hosts both Azure OpenAI and Content Understanding GA."
},
- "value": "[reference('avmAiServices_cu').outputs.name.value]"
+ "value": "[reference('avmAiServices').outputs.name.value]"
},
"AZURE_RESOURCE_GROUP": {
"type": "string",
diff --git a/infra/main.parameters.json b/infra/main.parameters.json
index 27461ece..44153d57 100644
--- a/infra/main.parameters.json
+++ b/infra/main.parameters.json
@@ -8,9 +8,6 @@
"location": {
"value": "${AZURE_LOCATION}"
},
- "contentUnderstandingLocation": {
- "value": "${AZURE_ENV_CU_LOCATION}"
- },
"azureAiServiceLocation": {
"value": "${AZURE_ENV_AI_SERVICE_LOCATION}"
},
diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json
index 7fdeab31..8e145a07 100644
--- a/infra/main.waf.parameters.json
+++ b/infra/main.waf.parameters.json
@@ -8,9 +8,6 @@
"location": {
"value": "${AZURE_LOCATION}"
},
- "contentUnderstandingLocation": {
- "value": "${AZURE_ENV_CU_LOCATION}"
- },
"azureAiServiceLocation": {
"value": "${AZURE_ENV_AI_SERVICE_LOCATION}"
},
diff --git a/infra/main_custom.bicep b/infra/main_custom.bicep
index b63bbace..fd462dc6 100644
--- a/infra/main_custom.bicep
+++ b/infra/main_custom.bicep
@@ -28,26 +28,20 @@ param solutionName string = 'cps'
param location string
@minLength(1)
-@description('Optional. Location for the Azure AI Content Understanding service deployment.')
-@allowed(['WestUS', 'SwedenCentral', 'AustraliaEast'])
-@metadata({
- azd: {
- type: 'location'
- }
-})
-param contentUnderstandingLocation string = 'WestUS'
-
@allowed([
'australiaeast'
- 'centralus'
- 'eastasia'
+ 'eastus'
'eastus2'
'japaneast'
- 'northeurope'
+ 'southcentralus'
'southeastasia'
+ 'swedencentral'
'uksouth'
+ 'westeurope'
+ 'westus'
+ 'westus3'
])
-@description('Required. Location for the Azure AI Services deployment.')
+@description('Required. Location for the Azure AI Services deployment. Must support both Azure OpenAI gpt-5.1 (GlobalStandard) and Azure AI Content Understanding GA. If the deploymentType param is set to Standard, override the metadata.azd.usageName below to reference OpenAI.Standard.gpt-5.1 instead.')
@metadata({
azd: {
type: 'location'
@@ -750,6 +744,16 @@ module avmAiServices 'modules/account/aifoundry.bicep' = {
roleDefinitionIdOrName: 'Azure AI Developer'
principalType: 'ServicePrincipal'
}
+ {
+ principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId!
+ roleDefinitionIdOrName: 'Cognitive Services User'
+ principalType: 'ServicePrincipal'
+ }
+ {
+ principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId!
+ roleDefinitionIdOrName: 'Cognitive Services User'
+ principalType: 'ServicePrincipal'
+ }
]
networkAcls: {
bypass: 'AzureServices'
@@ -819,84 +823,6 @@ module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoi
}
}
-module avmAiServices_cu 'br/public:avm/res/cognitive-services/account:0.14.2' = {
- name: take('avm.res.cognitive-services.account.content-understanding.${solutionSuffix}', 64)
-
- params: {
- name: 'aicu-${solutionSuffix}'
- location: contentUnderstandingLocation
- sku: 'S0'
- managedIdentities: {
- systemAssigned: false
- userAssignedResourceIds: [
- avmManagedIdentity.outputs.resourceId // Use the managed identity created above
- ]
- }
- kind: 'AIServices'
- tags: {
- app: solutionSuffix
- location: location
- }
- customSubDomainName: 'aicu-${solutionSuffix}'
- disableLocalAuth: true
- enableTelemetry: enableTelemetry
- networkAcls: {
- bypass: 'AzureServices'
- defaultAction: 'Allow' // Always allow for AI Services
- }
- roleAssignments: [
- {
- principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId!
- roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908'
- principalType: 'ServicePrincipal'
- }
- {
- principalId: avmContainerApp_Workflow.outputs.systemAssignedMIPrincipalId!
- roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908'
- principalType: 'ServicePrincipal'
- }
- ]
-
- publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled'
- }
-}
-
-module contentUnderstandingPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.12.0' = if (enablePrivateNetworking) {
- name: take('avm.res.network.private-endpoint.aicu-${solutionSuffix}', 64)
- params: {
- name: 'pep-aicu-${solutionSuffix}'
- location: location
- tags: tags
- customNetworkInterfaceName: 'nic-aicu-${solutionSuffix}'
- privateLinkServiceConnections: [
- {
- name: 'pep-aicu-${solutionSuffix}-cognitiveservices-connection'
- properties: {
- privateLinkServiceId: avmAiServices_cu.outputs.resourceId
- groupIds: ['account']
- }
- }
- ]
- privateDnsZoneGroup: {
- privateDnsZoneGroupConfigs: [
- {
- name: 'aicu-dns-zone-cognitiveservices'
- privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId
- }
- {
- name: 'ai-services-dns-zone-aiservices'
- privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId
- }
- {
- name: 'aicu-dns-zone-contentunderstanding'
- privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId
- }
- ]
- }
- subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId
- }
-}
-
// ========== Container App Environment ========== //
module avmContainerAppEnv 'br/public:avm/res/app/managed-environment:0.13.2' = {
name: take('avm.res.app.managed-environment.${solutionSuffix}', 64)
@@ -1431,7 +1357,7 @@ module avmAppConfig 'br/public:avm/res/app-configuration/configuration-store:0.9
}
{
name: 'APP_CONTENT_UNDERSTANDING_ENDPOINT'
- value: avmAiServices_cu.outputs.endpoint //TODO: replace with actual endpoint
+ value: avmAiServices.outputs.endpoint
}
{
name: 'APP_COSMOS_CONTAINER_PROCESS'
@@ -1711,7 +1637,6 @@ module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = {
}
dependsOn: [
cognitiveServicePrivateEndpoint
- contentUnderstandingPrivateEndpoint
]
}
@@ -1963,8 +1888,8 @@ output CONTAINER_REGISTRY_LOGIN_SERVER string = avmContainerRegistry.outputs.log
@description('The Azure Container Registry endpoint for AZD custom deployment.')
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = avmContainerRegistry.outputs.loginServer
-@description('The name of the Content Understanding AI Services account.')
-output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices_cu.outputs.name
+@description('The name of the AI Services account that hosts both Azure OpenAI and Content Understanding.')
+output CONTENT_UNDERSTANDING_ACCOUNT_NAME string = avmAiServices.outputs.name
@description('The resource group the resources were deployed into.')
output AZURE_RESOURCE_GROUP string = resourceGroup().name
diff --git a/src/ContentProcessor/src/libs/azure_helper/content_understanding.py b/src/ContentProcessor/src/libs/azure_helper/content_understanding.py
index 78cd0bfc..26c3a861 100644
--- a/src/ContentProcessor/src/libs/azure_helper/content_understanding.py
+++ b/src/ContentProcessor/src/libs/azure_helper/content_understanding.py
@@ -4,8 +4,8 @@
"""Azure Content Understanding REST client.
Manages analyzer lifecycle (create / list / delete) and document analysis
-operations against the Azure Content Understanding preview API, used by
-the extract pipeline step.
+operations against the Azure Content Understanding GA API
+(api-version=2025-11-01), used by the extract pipeline step.
"""
import json
@@ -22,7 +22,7 @@
class AzureContentUnderstandingHelper:
- """REST client for the Azure Content Understanding preview API.
+ """REST client for the Azure Content Understanding GA API.
Responsibilities:
1. Manage analyzer lifecycle (create, list, get, delete).
@@ -36,7 +36,7 @@ class AzureContentUnderstandingHelper:
def __init__(
self,
endpoint: str,
- api_version: str = "2024-12-01-preview",
+ api_version: str = "2025-11-01",
x_ms_useragent: str = "cps-contentunderstanding/client",
):
self.credential = get_azure_credential()
@@ -63,14 +63,21 @@ def _get_analyzer_list_url(self, endpoint, api_version):
def _get_analyze_url(self, endpoint, api_version, analyzer_id):
return f"{endpoint}/contentunderstanding/analyzers/{analyzer_id}:analyze?api-version={api_version}" # noqa
- def _get_training_data_config(
+ def _get_analyze_binary_url(self, endpoint, api_version, analyzer_id):
+ return f"{endpoint}/contentunderstanding/analyzers/{analyzer_id}:analyzeBinary?api-version={api_version}" # noqa
+
+ def _get_knowledge_source_config(
self, storage_container_sas_url, storage_container_path_prefix
):
- return {
- "containerUrl": storage_container_sas_url,
- "kind": "blob",
- "prefix": storage_container_path_prefix,
- }
+ # GA renamed the analyzer-template field `trainingData` (object) to
+ # `knowledgeSources` (array of source objects).
+ return [
+ {
+ "kind": "blob",
+ "containerUrl": storage_container_sas_url,
+ "prefix": storage_container_path_prefix,
+ }
+ ]
def _get_headers(self, api_token, x_ms_useragent):
"""Build default HTTP headers for Content Understanding requests.
@@ -164,7 +171,7 @@ def begin_create_analyzer(
training_storage_container_sas_url
and training_storage_container_path_prefix
): # noqa
- analyzer_template["trainingData"] = self._get_training_data_config(
+ analyzer_template["knowledgeSources"] = self._get_knowledge_source_config(
training_storage_container_sas_url,
training_storage_container_path_prefix,
)
@@ -204,7 +211,11 @@ def delete_analyzer(self, analyzer_id: str):
def begin_analyze_stream(self, analyzer_id: str, file_stream: bytes):
"""
- Begins the analysis of a file or URL using the specified analyzer.
+ Begins the analysis of a binary file stream using the specified analyzer.
+
+ In Content Understanding GA, raw byte uploads must target the
+ ``:analyzeBinary`` action (the ``:analyze`` action is JSON-only and
+ accepts a ``url`` in the request body).
Args:
analyzer_id (str): The ID of the analyzer to use.
@@ -214,13 +225,14 @@ def begin_analyze_stream(self, analyzer_id: str, file_stream: bytes):
Response: The response from the analysis request.
Raises:
- ValueError: If the file location is not a valid path or URL.
HTTPError: If the HTTP request returned an unsuccessful status code.
"""
headers = {"Content-Type": "application/octet-stream"}
headers.update(self._headers)
response = requests.post(
- url=self._get_analyze_url(self._endpoint, self._api_version, analyzer_id),
+ url=self._get_analyze_binary_url(
+ self._endpoint, self._api_version, analyzer_id
+ ),
headers=headers,
data=file_stream,
)
@@ -233,6 +245,10 @@ def begin_analyze(self, analyzer_id: str, file_location: str):
"""
Begins the analysis of a file or URL using the specified analyzer.
+ For local files, byte content is uploaded via the GA ``:analyzeBinary``
+ action; for HTTP/HTTPS URLs, the URL is sent as JSON to the ``:analyze``
+ action.
+
Args:
analyzer_id (str): The ID of the analyzer to use.
file_location (str): The path to the file or the URL to analyze.
@@ -244,34 +260,31 @@ def begin_analyze(self, analyzer_id: str, file_location: str):
ValueError: If the file location is not a valid path or URL.
HTTPError: If the HTTP request returned an unsuccessful status code.
"""
- data = None
if Path(file_location).exists():
with open(file_location, "rb") as file:
data = file.read()
headers = {"Content-Type": "application/octet-stream"}
- elif "https://" in file_location or "http://" in file_location:
- data = {"url": file_location}
- headers = {"Content-Type": "application/json"}
- else:
- raise ValueError("File location must be a valid path or URL.")
-
- headers.update(self._headers)
- if isinstance(data, dict):
+ headers.update(self._headers)
response = requests.post(
- url=self._get_analyze_url(
+ url=self._get_analyze_binary_url(
self._endpoint, self._api_version, analyzer_id
),
headers=headers,
- json=data,
+ data=data,
)
- else:
+ elif "https://" in file_location or "http://" in file_location:
+ data = {"url": file_location}
+ headers = {"Content-Type": "application/json"}
+ headers.update(self._headers)
response = requests.post(
url=self._get_analyze_url(
self._endpoint, self._api_version, analyzer_id
),
headers=headers,
- data=data,
+ json=data,
)
+ else:
+ raise ValueError("File location must be a valid path or URL.")
response.raise_for_status()
self._logger.info(
@@ -282,12 +295,19 @@ def begin_analyze(self, analyzer_id: str, file_location: str):
def get_image_from_analyze_operation(
self, analyze_response: Response, image_id: str
):
- """Retrieves an image from the analyze operation using the image ID.
+ """Retrieves a generated file (e.g., a rendered page image) from a
+ completed analyze operation by its file id / path.
+
+ In Content Understanding GA the file-retrieval URL changed from
+ ``{operationLocation}/images/{imageId}`` to
+ ``{operationLocation}/files/{fileId}`` (where ``operationLocation`` now
+ ends in ``/analyzerResults/{operationId}``).
+
Args:
analyze_response (Response): The response object from the analyze operation.
- image_id (str): The ID of the image to retrieve.
+ image_id (str): The id (or path) of the file to retrieve.
Returns:
- bytes: The image content as a byte string.
+ bytes: The file content as a byte string.
"""
operation_location = analyze_response.headers.get("operation-location", "")
if not operation_location:
@@ -296,7 +316,7 @@ def get_image_from_analyze_operation(
)
operation_location = operation_location.split("?api-version")[0]
image_retrieval_url = (
- f"{operation_location}/images/{image_id}?api-version={self._api_version}"
+ f"{operation_location}/files/{image_id}?api-version={self._api_version}"
)
try:
response = requests.get(url=image_retrieval_url, headers=self._headers)
diff --git a/src/ContentProcessor/src/libs/azure_helper/model/content_understanding.py b/src/ContentProcessor/src/libs/azure_helper/model/content_understanding.py
index cbffaf0e..3ca81b71 100644
--- a/src/ContentProcessor/src/libs/azure_helper/model/content_understanding.py
+++ b/src/ContentProcessor/src/libs/azure_helper/model/content_understanding.py
@@ -9,7 +9,7 @@
from typing import List, Optional
-from pydantic import BaseModel, ValidationInfo, field_validator
+from pydantic import BaseModel, Field, ValidationInfo, field_validator
class Span(BaseModel):
@@ -100,13 +100,13 @@ class Config:
class Page(BaseModel):
pageNumber: int
- angle: float
+ angle: Optional[float] = None
width: float
height: float
- spans: List[Span]
- words: List[Word]
- lines: Optional[List[Line]] = []
- paragraphs: Optional[List[Paragraph]] = []
+ spans: List[Span] = Field(default_factory=list)
+ words: List[Word] = Field(default_factory=list)
+ lines: List[Line] = Field(default_factory=list)
+ paragraphs: List[Paragraph] = Field(default_factory=list)
class DocumentContent(BaseModel):
@@ -116,13 +116,30 @@ class DocumentContent(BaseModel):
endPageNumber: int
unit: str
pages: List[Page]
+ paragraphs: List[Paragraph] = Field(default_factory=list)
+
+
+class Warning(BaseModel):
+ """Mirrors the Azure.Core.Foundations.Error shape returned in
+ ``ResultData.warnings`` by the Content Understanding GA API.
+
+ The API now emits structured warning objects (with ``code`` / ``message``
+ plus optional ``target`` / ``details``) instead of plain strings, so this
+ model accepts arbitrary nested error payloads via ``model_config``.
+ """
+
+ code: str
+ message: str
+ target: Optional[str] = None
+
+ model_config = {"extra": "allow"}
class ResultData(BaseModel):
analyzerId: str
apiVersion: str
createdAt: str
- warnings: List[str]
+ warnings: List[Warning] = Field(default_factory=list)
contents: List[DocumentContent]
diff --git a/src/ContentProcessor/tests/unit/azure_helper/test_content_understanding_model.py b/src/ContentProcessor/tests/unit/azure_helper/test_content_understanding_model.py
index 624f1063..8e042a30 100644
--- a/src/ContentProcessor/tests/unit/azure_helper/test_content_understanding_model.py
+++ b/src/ContentProcessor/tests/unit/azure_helper/test_content_understanding_model.py
@@ -13,6 +13,7 @@
Paragraph,
ResultData,
Span,
+ Warning,
Word,
)
@@ -163,7 +164,7 @@ def test_construction(self):
status="succeeded",
result=ResultData(
analyzerId="prebuilt",
- apiVersion="2024-01-01",
+ apiVersion="2025-11-01",
createdAt="2024-01-01T00:00:00Z",
warnings=[],
contents=[],
@@ -172,3 +173,50 @@ def test_construction(self):
assert result.id == "r-1"
assert result.status == "succeeded"
assert result.result.contents == []
+
+ def test_warnings_are_structured(self):
+ # In CU GA the `warnings` field switched from List[str] to a list of
+ # Azure.Core.Foundations.Error objects with code/message/target/details.
+ result = AnalyzedResult(
+ id="r-2",
+ status="succeeded",
+ result=ResultData(
+ analyzerId="prebuilt-documentAnalyzer",
+ apiVersion="2025-11-01",
+ createdAt="2025-11-01T00:00:00Z",
+ warnings=[
+ {
+ "code": "PageImageNotAvailable",
+ "message": "Generated image is not available for page 3.",
+ "target": "pages[2]",
+ "details": [],
+ }
+ ],
+ contents=[],
+ ),
+ )
+ assert len(result.result.warnings) == 1
+ warning = result.result.warnings[0]
+ assert isinstance(warning, Warning)
+ assert warning.code == "PageImageNotAvailable"
+ assert warning.message.startswith("Generated image")
+ assert warning.target == "pages[2]"
+
+
+class TestPageGAOptionals:
+ """In CU GA the `angle`, `spans`, and `words` fields on Page are optional
+ (the prebuilt-documentAnalyzer can omit them when the underlying source
+ has no OCR layer)."""
+
+ def test_page_can_be_constructed_without_angle_spans_words(self):
+ page = Page(
+ pageNumber=1,
+ width=8.5,
+ height=11.0,
+ )
+ assert page.pageNumber == 1
+ assert page.angle is None
+ assert page.spans == []
+ assert page.words == []
+ assert page.lines == []
+ assert page.paragraphs == []
diff --git a/src/tests/ContentProcessor/azure_helper/test_content_understanding_model.py b/src/tests/ContentProcessor/azure_helper/test_content_understanding_model.py
index 624f1063..8e042a30 100644
--- a/src/tests/ContentProcessor/azure_helper/test_content_understanding_model.py
+++ b/src/tests/ContentProcessor/azure_helper/test_content_understanding_model.py
@@ -13,6 +13,7 @@
Paragraph,
ResultData,
Span,
+ Warning,
Word,
)
@@ -163,7 +164,7 @@ def test_construction(self):
status="succeeded",
result=ResultData(
analyzerId="prebuilt",
- apiVersion="2024-01-01",
+ apiVersion="2025-11-01",
createdAt="2024-01-01T00:00:00Z",
warnings=[],
contents=[],
@@ -172,3 +173,50 @@ def test_construction(self):
assert result.id == "r-1"
assert result.status == "succeeded"
assert result.result.contents == []
+
+ def test_warnings_are_structured(self):
+ # In CU GA the `warnings` field switched from List[str] to a list of
+ # Azure.Core.Foundations.Error objects with code/message/target/details.
+ result = AnalyzedResult(
+ id="r-2",
+ status="succeeded",
+ result=ResultData(
+ analyzerId="prebuilt-documentAnalyzer",
+ apiVersion="2025-11-01",
+ createdAt="2025-11-01T00:00:00Z",
+ warnings=[
+ {
+ "code": "PageImageNotAvailable",
+ "message": "Generated image is not available for page 3.",
+ "target": "pages[2]",
+ "details": [],
+ }
+ ],
+ contents=[],
+ ),
+ )
+ assert len(result.result.warnings) == 1
+ warning = result.result.warnings[0]
+ assert isinstance(warning, Warning)
+ assert warning.code == "PageImageNotAvailable"
+ assert warning.message.startswith("Generated image")
+ assert warning.target == "pages[2]"
+
+
+class TestPageGAOptionals:
+ """In CU GA the `angle`, `spans`, and `words` fields on Page are optional
+ (the prebuilt-documentAnalyzer can omit them when the underlying source
+ has no OCR layer)."""
+
+ def test_page_can_be_constructed_without_angle_spans_words(self):
+ page = Page(
+ pageNumber=1,
+ width=8.5,
+ height=11.0,
+ )
+ assert page.pageNumber == 1
+ assert page.angle is None
+ assert page.spans == []
+ assert page.words == []
+ assert page.lines == []
+ assert page.paragraphs == []