diff --git a/content-gen/docs/AVMPostDeploymentGuide.md b/content-gen/docs/AVMPostDeploymentGuide.md new file mode 100644 index 000000000..66d2faa71 --- /dev/null +++ b/content-gen/docs/AVMPostDeploymentGuide.md @@ -0,0 +1,211 @@ +# AVM Post Deployment Guide + +> **📋 Note**: This guide is specifically for post-deployment steps after using the AVM template. For complete deployment from scratch, see the main [Deployment Guide](./DEPLOYMENT.md). + +--- + +This document provides guidance on post-deployment steps after deploying the Content Generation solution accelerator from the [AVM (Azure Verified Modules) repository](https://github.com/Azure/bicep-registry-modules/tree/main/avm/ptn/sa/content-generation). + +## Overview + +After successfully deploying the Content Generation Solution Accelerator using the AVM template, you'll need to complete some configuration steps to make the solution fully operational. The AVM deployment provisions all required Azure resources, and the post-deployment process will upload sample data, create search indexes, and verify the application is ready to use. + +--- + +## Prerequisites + +Before starting the post-deployment process, ensure you have the following: + +### 1. Azure Subscription & Permissions + +You need access to an [Azure subscription](https://azure.microsoft.com/free/) with permissions to: +- Create resource groups and resources +- Create app registrations +- Assign roles at the resource group level (Contributor + RBAC) + +📖 Follow the steps in [Azure Account Set Up](./AzureAccountSetUp.md) for detailed instructions. + +### 2. Deployed Infrastructure + +A successful Content Generation solution accelerator deployment from the [AVM repository](https://github.com/Azure/bicep-registry-modules/tree/main/avm/ptn/sa/content-generation). + +The deployment should have created the following resources: +- Azure App Service (frontend web app) +- Azure Container Instance (backend API) +- Azure AI Foundry (AI orchestration) +- Azure OpenAI Service (GPT and Image models) +- Azure Cosmos DB (product catalog and conversations) +- Azure Blob Storage (product images and generated images) +- Azure AI Search (product search index) +- User Assigned Managed Identity +- App Service Plan + +**Optional resources** (depending on deployment parameters): +- Log Analytics Workspace and Application Insights (if monitoring is enabled) +- Virtual Network, Private DNS Zones, and Private Endpoints (if private networking is enabled) +- Azure Bastion and Jumpbox VM (if enabled for private network administration) + +**Important:** The deployment references an **existing Azure Container Registry** (specified via the `acrName` parameter) that must contain pre-built container images (`content-gen-app` and `content-gen-api`). The ACR is not created by this deployment. + +### 3. Required Tools + +Ensure the following tools are installed on your machine: + +| Tool | Version | Download Link | +|------|---------|---------------| +| PowerShell | v7.0+ | [Install PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.5) | +| Azure CLI | v2.50+ | [Install Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) | +| Python | 3.11+ | [Download Python](https://www.python.org/downloads/) | +| Git | Latest | [Download Git](https://git-scm.com/downloads) | + +#### Important Note for PowerShell Users + +If you encounter issues running PowerShell scripts due to execution policy restrictions, you can temporarily adjust the `ExecutionPolicy` by running the following command in an elevated PowerShell session: + +```powershell +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +``` + +This will allow the scripts to run for the current session without permanently changing your system's policy. + +--- + +## Post-Deployment Steps + +### Step 1: Clone the Repository + +Clone this repository to access the post-deployment scripts and sample data: + +```powershell +git clone https://github.com/microsoft/content-generation-solution-accelerator.git +cd content-generation-solution-accelerator/content-gen +``` + +--- + +### Step 2: Run the Post-Deployment Script + +The AVM deployment provisions the Azure infrastructure but does NOT include automated post-deployment hooks. You need to manually run the post-deployment script to upload sample data and create search indexes. + +> **📝 Note**: Unlike `azd up` deployments which run post-deployment hooks automatically via `azure.yaml`, AVM deployments require manual execution of the post-deployment script. + +#### 2.1 Login to Azure + +```shell +az login +``` + +> 💡 **Tip**: If using VS Code Web or environments without browser access, use device code authentication: +> ```shell +> az login --use-device-code +> ``` + +#### 2.2 Set Up Environment + +Navigate to the `content-gen` directory and create a Python virtual environment: + +**For Windows (PowerShell):** +```powershell +python -m venv .venv +.\.venv\Scripts\Activate.ps1 +pip install -r ./scripts/requirements-post-deploy.txt +``` + +**For Linux/Mac (bash):** +```bash +python3 -m venv .venv +source .venv/bin/activate +pip install -r ./scripts/requirements-post-deploy.txt +``` + +#### 2.3 Execute the Post-Deployment Script + +Run the post-deployment script with your resource group name. The script will automatically retrieve resource names from the Azure deployment outputs. + +**For Windows (PowerShell):** +```powershell +python ./scripts/post_deploy.py -g --skip-tests +``` + +**For Linux/Mac (bash):** +```bash +python3 ./scripts/post_deploy.py -g --skip-tests +``` + +**Example:** +```powershell +python ./scripts/post_deploy.py -g rg-contentgen-prod --skip-tests +``` + +> ⚠️ **Important**: The script uses Azure CLI authentication and will automatically discover resource names from deployment outputs. Ensure you're logged in with `az login` before running. + +**How it works:** +- The script queries the deployment outputs using the resource group name +- It automatically retrieves App Service, Storage Account, Cosmos DB, and AI Search names +- No need to manually specify individual resource names + +**Alternative:** If you prefer to specify resources explicitly, you can use environment variables or command-line arguments: +```powershell +# Using environment variables +$env:RESOURCE_GROUP_NAME = "rg-contentgen-prod" +$env:APP_SERVICE_NAME = "app-contentgen-abc123" +$env:AZURE_BLOB_ACCOUNT_NAME = "stcontentgenabc123" +$env:COSMOSDB_ACCOUNT_NAME = "cosmos-contentgen-abc123" +$env:AI_SEARCH_SERVICE_NAME = "search-contentgen-abc123" +python ./scripts/post_deploy.py --skip-tests +``` + +The script will: +- Upload sample product data to Cosmos DB +- Upload sample product images to Blob Storage +- Create and populate the Azure AI Search index +- Verify all connections and configurations + +--- + +### Step 3: Access the Application + +1. Navigate to the [Azure Portal](https://portal.azure.com) +2. Open the **resource group** created during deployment +3. Locate the **App Service** (name typically starts with `app-contentgen-`) +4. Copy the **URL** from the Overview page (format: `https://app-contentgen-.azurewebsites.net`) +5. Open the URL in your browser to access the application + +> 📝 **Note**: It may take a few minutes for the App Service to start up after deployment. + +--- + +### Step 4: Configure Authentication (Optional) + +If you want to enable authentication for your application, follow the [App Authentication Guide](./AppAuthentication.md). + +> **⚠️ Important**: Authentication changes can take up to 10 minutes to propagate. + +--- + +### Step 5: Verify Data Processing + +Confirm your deployment is working correctly: + +| Check | Location | How to Verify | +|-------|----------|---------------| +| ✅ Sample data uploaded | Azure Cosmos DB | Navigate to Cosmos DB → Data Explorer → Check `products` and `conversations` containers | +| ✅ Sample images uploaded | Azure Blob Storage | Navigate to Storage Account → Containers → Check `product-images` container | +| ✅ AI Search index created | Azure AI Search | Navigate to AI Search → Indexes → Verify `products-index` exists and has documents | +| ✅ Application loads | App Service URL | Open the web app URL and verify the welcome screen appears | + +--- + +## Getting Started + +To learn how to use the Content Generation solution and try sample workflows, see the [Sample Workflow](./DEPLOYMENT.md#sample-workflow) section in the main Deployment Guide. + +--- + +## Clean Up Resources + +If you need to delete the resources after testing or a failed deployment: + +Follow the steps in [Delete Resource Group](./DeleteResourceGroup.md) to clean up all deployed resources. + +> ⚠️ **Warning**: Deleting the resource group will permanently delete all resources and data. This action cannot be undone. diff --git a/content-gen/infra/main.bicep b/content-gen/infra/main.bicep index c3b840d2c..a9ec5e738 100644 --- a/content-gen/infra/main.bicep +++ b/content-gen/infra/main.bicep @@ -128,13 +128,13 @@ param enableRedundancy bool = false @description('Optional. Enable private networking for applicable resources (WAF-aligned).') param enablePrivateNetworking bool = false -@description('Required. The existing Container Registry name (without .azurecr.io). Must contain pre-built images: content-gen-app and content-gen-api.') +@description('Optional. The existing Container Registry name (without .azurecr.io). Must contain pre-built images: content-gen-app and content-gen-api.') param acrName string = 'contentgencontainerreg' @description('Optional. Image Tag.') param imageTag string = 'latest' -@description('Optional. Enable/Disable usage telemetry.') +@description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true @description('Optional. Created by user name.') @@ -261,7 +261,14 @@ var imageModelDeployment = imageModelChoice != 'none' ? [ var aiFoundryAiServicesModelDeployment = concat(baseModelDeployments, imageModelDeployment) var aiFoundryAiProjectDescription = 'Content Generation AI Foundry Project' -var existingTags = resourceGroup().tags ?? {} + +// Reference existing resource group to access current tags +resource existingResourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' existing = { + scope: subscription() + name: resourceGroup().name +} + +var existingTags = existingResourceGroup.tags ?? {} // ============== // // Resources // @@ -269,7 +276,7 @@ var existingTags = resourceGroup().tags ?? {} #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { - name: '46d3xbcp.ptn.sa-contentgen.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, solutionLocation), 0, 4)}' + name: '46d3xbcp.ptn.sa-contentgeneration.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, solutionLocation), 0, 4)}' properties: { mode: 'Incremental' template: { @@ -287,7 +294,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } // ========== Resource Group Tag ========== // -resource resourceGroupTags 'Microsoft.Resources/tags@2021-04-01' = { +resource resourceGroupTags 'Microsoft.Resources/tags@2025-04-01' = { name: 'default' properties: { tags: union( @@ -304,7 +311,7 @@ resource resourceGroupTags 'Microsoft.Resources/tags@2021-04-01' = { // ========== Log Analytics Workspace ========== // var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' -module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.14.2' = if (enableMonitoring && !useExistingLogAnalytics) { +module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.15.0' = if (enableMonitoring) { name: take('avm.res.operational-insights.workspace.${logAnalyticsWorkspaceResourceName}', 64) params: { name: logAnalyticsWorkspaceResourceName @@ -315,7 +322,7 @@ module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0 dataRetention: 365 features: { enableLogAccessUsingOnlyResourcePermissions: true } diagnosticSettings: [{ useThisWorkspace: true }] - dailyQuotaGb: enableRedundancy ? 10 : null + dailyQuotaGb: enableRedundancy ? '10' : null replication: enableRedundancy ? { enabled: true @@ -350,7 +357,7 @@ module applicationInsights 'br/public:avm/res/insights/component:0.7.1' = if (en // ========== User Assigned Identity ========== // var userAssignedIdentityResourceName = 'id-${solutionSuffix}' -module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.3' = { +module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.5.0' = { name: take('avm.res.managed-identity.user-assigned-identity.${userAssignedIdentityResourceName}', 64) params: { name: userAssignedIdentityResourceName @@ -415,12 +422,13 @@ module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.8.0' = [ ] // ========== AI Foundry: AI Services ========== // -module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.14.0' = if (!useExistingAiFoundryAiProject) { +module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.14.1' = if (!useExistingAiFoundryAiProject) { name: take('avm.res.cognitive-services.account.${aiFoundryAiServicesResourceName}', 64) params: { name: aiFoundryAiServicesResourceName location: azureAiServiceLocation tags: tags + enableTelemetry: enableTelemetry sku: 'S0' kind: 'AIServices' disableLocalAuth: true @@ -447,8 +455,8 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.14.0' virtualNetworkRules: [] ipRules: [] } - managedIdentities: { - userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] + managedIdentities: { + userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] } roleAssignments: [ { @@ -478,12 +486,13 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.14.0' } // Create private endpoint for AI Services AFTER the account is fully provisioned -module aiServicesPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.11.0' = if (!useExistingAiFoundryAiProject && enablePrivateNetworking) { +module aiServicesPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.11.1' = if (!useExistingAiFoundryAiProject && enablePrivateNetworking) { name: take('pep-ai-services-${aiFoundryAiServicesResourceName}', 64) params: { name: 'pep-${aiFoundryAiServicesResourceName}' location: solutionLocation tags: tags + enableTelemetry: enableTelemetry subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId privateLinkServiceConnections: [ { @@ -496,13 +505,13 @@ module aiServicesPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.1 ] privateDnsZoneGroup: { privateDnsZoneGroupConfigs: [ - { + { name: 'cognitiveservices' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId } - { + { name: 'openai' - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId } ] } @@ -540,7 +549,7 @@ module existingAiServicesRoleAssignments 'modules/deploy_foundry_role_assignment } // ========== AI Search ========== // -module aiSearch 'br/public:avm/res/search/search-service:0.11.1' = { +module aiSearch 'br/public:avm/res/search/search-service:0.12.0' = { name: take('avm.res.search.search-service.${aiSearchName}', 64) params: { name: aiSearchName @@ -548,9 +557,9 @@ module aiSearch 'br/public:avm/res/search/search-service:0.11.1' = { tags: tags enableTelemetry: enableTelemetry sku: enableScalability ? 'standard' : 'basic' - replicaCount: enableRedundancy ? 2 : 1 + replicaCount: enableRedundancy ? 3 : 1 partitionCount: 1 - hostingMode: 'default' + hostingMode: 'Default' semanticSearch: 'free' authOptions: { aadOrApiKey: { @@ -577,7 +586,7 @@ module aiSearch 'br/public:avm/res/search/search-service:0.11.1' = { } // ========== AI Search Connection to AI Services ========== // -resource aiSearchFoundryConnection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-04-01-preview' = if (!useExistingAiFoundryAiProject) { +resource aiSearchFoundryConnection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-09-01' = if (!useExistingAiFoundryAiProject) { name: '${aiFoundryAiServicesResourceName}/${aiFoundryAiProjectResourceName}/${aiSearchConnectionName}' properties: { category: 'CognitiveSearch' @@ -598,7 +607,7 @@ var productImagesContainer = 'product-images' var generatedImagesContainer = 'generated-images' var dataContainer = 'data' -module storageAccount 'br/public:avm/res/storage/storage-account:0.30.0' = { +module storageAccount 'br/public:avm/res/storage/storage-account:0.31.1' = { name: take('avm.res.storage.storage-account.${storageAccountName}', 64) params: { name: storageAccountName @@ -643,17 +652,19 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.30.0' = { } allowBlobPublicAccess: false publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' - privateEndpoints: enablePrivateNetworking ? [ - { - service: 'blob' - subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId } - ] - } - } - ] : null + privateEndpoints: enablePrivateNetworking + ? [ + { + service: 'blob' + subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.storageBlob]!.outputs.resourceId } + ] + } + } + ] + : null diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null } } @@ -738,23 +749,25 @@ module cosmosDB 'br/public:avm/res/document-db/database-account:0.18.0' = { isZoneRedundant: false } ] - privateEndpoints: enablePrivateNetworking ? [ - { - service: 'Sql' - subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId } - ] - } - } - ] : null + privateEndpoints: enablePrivateNetworking + ? [ + { + service: 'Sql' + subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDB]!.outputs.resourceId } + ] + } + } + ] + : null } } // ========== App Service Plan ========== // var webServerFarmResourceName = 'asp-${solutionSuffix}' -module webServerFarm 'br/public:avm/res/web/serverfarm:0.5.0' = { +module webServerFarm 'br/public:avm/res/web/serverfarm:0.7.0' = { name: take('avm.res.web.serverfarm.${webServerFarmResourceName}', 64) params: { name: webServerFarmResourceName @@ -765,7 +778,7 @@ module webServerFarm 'br/public:avm/res/web/serverfarm:0.5.0' = { kind: 'linux' diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null skuName: enableScalability || enableRedundancy ? 'P1v3' : 'B1' - skuCapacity: 1 + skuCapacity: enableRedundancy ? 2 : 1 zoneRedundant: enableRedundancy ? true : false } scope: resourceGroup(resourceGroup().name) @@ -777,7 +790,7 @@ var webSiteResourceName = 'app-${solutionSuffix}' var aciPrivateIpFallback = '10.0.4.4' var aciPublicFqdnFallback = '${containerInstanceName}.${solutionLocation}.azurecontainer.io' // For private networking use IP, for public use FQDN -var aciBackendUrl = enablePrivateNetworking +var aciBackendUrl = enablePrivateNetworking ? 'http://${aciPrivateIpFallback}:8000' : 'http://${aciPublicFqdnFallback}:8000' module webSite 'modules/web-sites.bicep' = { @@ -797,24 +810,30 @@ module webSite 'modules/web-sites.bicep' = { ftpsState: 'FtpsOnly' } virtualNetworkSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.webSubnetResourceId : null - configs: concat([ - { - // Frontend container proxies to ACI backend (both modes) - name: 'appsettings' - properties: { - DOCKER_REGISTRY_SERVER_URL: 'https://${acrResourceName}.azurecr.io' - BACKEND_URL: aciBackendUrl - AZURE_CLIENT_ID: userAssignedIdentity.outputs.clientId + configs: concat( + [ + { + // Frontend container proxies to ACI backend (both modes) + name: 'appsettings' + properties: { + DOCKER_REGISTRY_SERVER_URL: 'https://${acrResourceName}.azurecr.io' + BACKEND_URL: aciBackendUrl + AZURE_CLIENT_ID: userAssignedIdentity.outputs.clientId + } + applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null } - applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null - } - ], enableMonitoring ? [ - { - name: 'logs' - properties: {} - } - ] : []) + ], + enableMonitoring + ? [ + { + name: 'logs' + properties: {} + } + ] + : [] + ) enableMonitoring: enableMonitoring + enableTelemetry: enableTelemetry diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null vnetRouteAllEnabled: enablePrivateNetworking vnetImagePullEnabled: enablePrivateNetworking @@ -836,7 +855,6 @@ module containerInstance 'modules/container-instance.bicep' = { port: 8000 // Only pass subnetResourceId when private networking is enabled subnetResourceId: enablePrivateNetworking ? virtualNetwork!.outputs.aciSubnetResourceId : '' - registryServer: '${acrResourceName}.azurecr.io' userAssignedIdentityResourceId: userAssignedIdentity.outputs.resourceId enableTelemetry: enableTelemetry environmentVariables: [ @@ -844,7 +862,10 @@ module containerInstance 'modules/container-instance.bicep' = { { name: 'AZURE_OPENAI_ENDPOINT', value: 'https://${aiFoundryAiServicesResourceName}.openai.azure.com/' } { name: 'AZURE_OPENAI_GPT_MODEL', value: gptModelName } { name: 'AZURE_OPENAI_IMAGE_MODEL', value: imageModelConfig[imageModelChoice].name } - { name: 'AZURE_OPENAI_GPT_IMAGE_ENDPOINT', value: imageModelChoice != 'none' ? 'https://${aiFoundryAiServicesResourceName}.openai.azure.com/' : '' } + { + name: 'AZURE_OPENAI_GPT_IMAGE_ENDPOINT' + value: imageModelChoice != 'none' ? 'https://${aiFoundryAiServicesResourceName}.openai.azure.com/' : '' + } { name: 'AZURE_OPENAI_API_VERSION', value: azureOpenaiAPIVersion } // Azure Cosmos DB Settings { name: 'AZURE_COSMOS_ENDPOINT', value: 'https://cosmos-${solutionSuffix}.documents.azure.com:443/' } diff --git a/content-gen/infra/main.json b/content-gen/infra/main.json index d530fd4b2..93671b596 100644 --- a/content-gen/infra/main.json +++ b/content-gen/infra/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "14662930066054172114" + "templateHash": "315804383926522486" }, "name": "Intelligent Content Generation Accelerator", "description": "Solution Accelerator for multimodal marketing content generation using Microsoft Agent Framework.\n" @@ -222,7 +222,7 @@ "type": "string", "defaultValue": "contentgencontainerreg", "metadata": { - "description": "Required. The existing Container Registry name (without .azurecr.io). Must contain pre-built images: content-gen-app and content-gen-api." + "description": "Optional. The existing Container Registry name (without .azurecr.io). Must contain pre-built images: content-gen-app and content-gen-api." } }, "imageTag": { @@ -236,7 +236,7 @@ "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry." + "description": "Optional. Enable/Disable usage telemetry for module." } }, "createdBy": { @@ -321,7 +321,6 @@ "imageModelDeployment": "[if(not(equals(parameters('imageModelChoice'), 'none')), createArray(createObject('format', 'OpenAI', 'name', variables('imageModelConfig')[parameters('imageModelChoice')].name, 'model', variables('imageModelConfig')[parameters('imageModelChoice')].name, 'sku', createObject('name', variables('imageModelConfig')[parameters('imageModelChoice')].sku, 'capacity', parameters('imageModelCapacity')), 'version', variables('imageModelConfig')[parameters('imageModelChoice')].version, 'raiPolicyName', 'Microsoft.Default')), createArray())]", "aiFoundryAiServicesModelDeployment": "[concat(variables('baseModelDeployments'), variables('imageModelDeployment'))]", "aiFoundryAiProjectDescription": "Content Generation AI Foundry Project", - "existingTags": "[coalesce(resourceGroup().tags, createObject())]", "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", "applicationInsightsResourceName": "[format('appi-{0}', variables('solutionSuffix'))]", "userAssignedIdentityResourceName": "[format('id-{0}', variables('solutionSuffix'))]", @@ -353,11 +352,18 @@ "containerInstanceName": "[format('aci-{0}', variables('solutionSuffix'))]" }, "resources": { + "existingResourceGroup": { + "existing": true, + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2024-03-01", + "subscriptionId": "[subscription().subscriptionId]", + "name": "[resourceGroup().name]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.ptn.sa-contentgen.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, variables('solutionLocation')), 0, 4))]", + "name": "[format('46d3xbcp.ptn.sa-contentgeneration.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, variables('solutionLocation')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -375,16 +381,19 @@ }, "resourceGroupTags": { "type": "Microsoft.Resources/tags", - "apiVersion": "2021-04-01", + "apiVersion": "2025-04-01", "name": "default", "properties": { - "tags": "[union(variables('existingTags'), parameters('tags'), createObject('TemplateName', 'ContentGen', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy')))]" - } + "tags": "[union(coalesce(reference('existingResourceGroup', '2024-03-01', 'full').tags, createObject()), parameters('tags'), createObject('TemplateName', 'ContentGen', 'Type', if(parameters('enablePrivateNetworking'), 'WAF', 'Non-WAF'), 'CreatedBy', parameters('createdBy')))]" + }, + "dependsOn": [ + "existingResourceGroup" + ] }, "aiSearchFoundryConnection": { "condition": "[not(variables('useExistingAiFoundryAiProject'))]", "type": "Microsoft.CognitiveServices/accounts/projects/connections", - "apiVersion": "2025-04-01-preview", + "apiVersion": "2025-09-01", "name": "[format('{0}/{1}/{2}', variables('aiFoundryAiServicesResourceName'), variables('aiFoundryAiProjectResourceName'), variables('aiSearchConnectionName'))]", "properties": { "category": "CognitiveSearch", @@ -402,7 +411,7 @@ ] }, "logAnalyticsWorkspace": { - "condition": "[and(parameters('enableMonitoring'), not(variables('useExistingLogAnalytics')))]", + "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", "name": "[take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)]", @@ -442,7 +451,7 @@ } ] }, - "dailyQuotaGb": "[if(parameters('enableRedundancy'), createObject('value', 10), createObject('value', null()))]", + "dailyQuotaGb": "[if(parameters('enableRedundancy'), createObject('value', '10'), createObject('value', null()))]", "replication": "[if(parameters('enableRedundancy'), createObject('value', createObject('enabled', true(), 'location', variables('replicaLocation'))), createObject('value', null()))]", "publicNetworkAccessForIngestion": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", "publicNetworkAccessForQuery": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]" @@ -455,7 +464,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "3322296220118676013" + "templateHash": "14099489006827800075" }, "name": "Log Analytics Workspaces", "description": "This module deploys a Log Analytics Workspace." @@ -896,7 +905,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-02-01#properties/tags" + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" }, "description": "Optional. Tags to configure in the resource." }, @@ -1557,11 +1566,10 @@ } }, "dailyQuotaGb": { - "type": "int", - "defaultValue": -1, - "minValue": -1, + "type": "string", + "defaultValue": "-1", "metadata": { - "description": "Optional. The workspace daily quota for ingestion." + "description": "Optional. The workspace daily quota for ingestion in GB. Supports decimal values. Example: '0.5' for 0.5 GB, '2' for 2 GB. Default is '-1' (no limit)." } }, "defaultDataCollectionRuleResourceId": { @@ -1654,7 +1662,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces@2025-02-01#properties/tags" + "source": "Microsoft.OperationalInsights/workspaces@2025-07-01#properties/tags" }, "description": "Optional. Tags of the resource." }, @@ -1698,7 +1706,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.14.2', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.15.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1734,7 +1742,7 @@ }, "retentionInDays": "[parameters('dataRetention')]", "workspaceCapping": { - "dailyQuotaGb": "[parameters('dailyQuotaGb')]" + "dailyQuotaGb": "[json(parameters('dailyQuotaGb'))]" }, "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", @@ -1867,7 +1875,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "15555486835943827858" + "templateHash": "140290971998938797" }, "name": "Log Analytics Workspace Storage Insight Configs", "description": "This module deploys a Log Analytics Workspace Storage Insight Config." @@ -1916,7 +1924,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-02-01#properties/tags" + "source": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2025-07-01#properties/tags" }, "description": "Optional. Tags to configure in the resource." }, @@ -1927,18 +1935,18 @@ "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" }, "workspace": { "existing": true, "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[parameters('logAnalyticsWorkspaceName')]" }, "storageinsightconfig": { "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "tags": "[parameters('tags')]", "properties": { @@ -1946,7 +1954,7 @@ "tables": "[parameters('tables')]", "storageAccount": { "id": "[parameters('storageAccountResourceId')]", - "key": "[listKeys('storageAccount', '2024-01-01').keys[0].value]" + "key": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" } } } @@ -2015,7 +2023,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "8517561285031465616" + "templateHash": "14482465616812596213" }, "name": "Log Analytics Workspace Linked Services", "description": "This module deploys a Log Analytics Workspace Linked Service." @@ -2051,7 +2059,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-02-01#properties/tags" + "source": "Microsoft.OperationalInsights/workspaces/linkedServices@2025-07-01#properties/tags" }, "description": "Optional. Tags to configure in the resource." }, @@ -2062,12 +2070,12 @@ "workspace": { "existing": true, "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[parameters('logAnalyticsWorkspaceName')]" }, "linkedService": { "type": "Microsoft.OperationalInsights/workspaces/linkedServices", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "tags": "[parameters('tags')]", "properties": { @@ -2137,7 +2145,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "3889914477453955601" + "templateHash": "14864721709229272590" }, "name": "Log Analytics Workspace Linked Storage Accounts", "description": "This module deploys a Log Analytics Workspace Linked Storage Account." @@ -2176,12 +2184,12 @@ "workspace": { "existing": true, "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[parameters('logAnalyticsWorkspaceName')]" }, "linkedStorageAccount": { "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "properties": { "storageAccountIds": "[parameters('storageAccountIds')]" @@ -2270,7 +2278,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "3727577253995784529" + "templateHash": "17904092372918022238" }, "name": "Log Analytics Workspace Saved Searches", "description": "This module deploys a Log Analytics Workspace Saved Search." @@ -2310,7 +2318,7 @@ "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-02-01#properties/properties/properties/tags" + "source": "Microsoft.OperationalInsights/workspaces/savedSearches@2025-07-01#properties/properties/properties/tags" }, "description": "Optional. Tags to configure in the resource." }, @@ -2349,12 +2357,12 @@ "workspace": { "existing": true, "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[parameters('logAnalyticsWorkspaceName')]" }, "savedSearch": { "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "properties": { "etag": "[parameters('etag')]", @@ -2436,7 +2444,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "6434695407713682713" + "templateHash": "17943947755417749524" }, "name": "Log Analytics Workspace Data Exports", "description": "This module deploys a Log Analytics Workspace Data Export." @@ -2518,12 +2526,12 @@ "workspace": { "existing": true, "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[parameters('workspaceName')]" }, "dataExport": { "type": "Microsoft.OperationalInsights/workspaces/dataExports", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", "properties": { "destination": "[parameters('destination')]", @@ -2629,7 +2637,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "8636447638029661740" + "templateHash": "15360290236166491819" }, "name": "Log Analytics Workspace Datasources", "description": "This module deploys a Log Analytics Workspace Data Source." @@ -2668,7 +2676,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-02-01#properties/tags" + "source": "Microsoft.OperationalInsights/workspaces/dataSources@2025-07-01#properties/tags" }, "description": "Optional. Tags to configure in the resource." }, @@ -2756,12 +2764,12 @@ "workspace": { "existing": true, "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[parameters('logAnalyticsWorkspaceName')]" }, "dataSource": { "type": "Microsoft.OperationalInsights/workspaces/dataSources", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", "kind": "[parameters('kind')]", "tags": "[parameters('tags')]", @@ -2859,7 +2867,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "13928174215528939368" + "templateHash": "18383178824663161801" }, "name": "Log Analytics Workspace Tables", "description": "This module deploys a Log Analytics Workspace Table." @@ -3208,12 +3216,12 @@ "workspace": { "existing": true, "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[parameters('workspaceName')]" }, "table": { "type": "Microsoft.OperationalInsights/workspaces/tables", - "apiVersion": "2025-02-01", + "apiVersion": "2025-07-01", "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", "properties": { "plan": "[parameters('plan')]", @@ -4326,7 +4334,7 @@ "_generator": { "name": "bicep", "version": "0.39.26.7824", - "templateHash": "1856697743030659118" + "templateHash": "7591858083424858339" }, "name": "User Assigned Identities", "description": "This module deploys a User Assigned Identity." @@ -4538,6 +4546,17 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "isolationScope": { + "type": "string", + "nullable": true, + "allowedValues": [ + "None", + "Regional" + ], + "metadata": { + "description": "Optional. Enum to configure regional restrictions on identity assignment, as necessary. Allowed values: \"None\", \"Regional\"." + } } }, "variables": { @@ -4563,7 +4582,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.4.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -4584,7 +4603,8 @@ "apiVersion": "2024-11-30", "name": "[parameters('name')]", "location": "[parameters('location')]", - "tags": "[parameters('tags')]" + "tags": "[parameters('tags')]", + "properties": "[if(not(equals(parameters('isolationScope'), null())), createObject('isolationScope', parameters('isolationScope')), createObject())]" }, "userAssignedIdentity_lock": { "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", @@ -10775,6 +10795,9 @@ "tags": { "value": "[parameters('tags')]" }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, "sku": { "value": "S0" }, @@ -10849,8 +10872,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "7191594406492701501" + "version": "0.39.26.7824", + "templateHash": "6544538318162038728" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service." @@ -12212,7 +12235,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('0.14.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('0.14.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -13076,8 +13099,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.38.33.27573", - "templateHash": "1394089926798493893" + "version": "0.39.26.7824", + "templateHash": "356315690886888607" } }, "definitions": { @@ -13273,6 +13296,22 @@ "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())]" } } } @@ -13302,6 +13341,9 @@ "tags": { "value": "[parameters('tags')]" }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, "subnetResourceId": { "value": "[reference('virtualNetwork').outputs.pepsSubnetResourceId.value]" }, @@ -13340,8 +13382,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint." @@ -13368,115 +13410,8 @@ } }, "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type of a private dns zone group." } }, "lockType": { @@ -13500,12 +13435,19 @@ "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.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -13527,6 +13469,7 @@ } }, "metadata": { + "description": "The type of a private DNS zone group configuration.", "__bicep_imported_from!": { "sourceTemplate": "private-dns-zone-group/main.bicep" } @@ -13603,7 +13546,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -13640,13 +13583,13 @@ }, "ipConfigurations": { "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, "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", @@ -13681,40 +13624,43 @@ }, "tags": { "type": "object", - "nullable": true, "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", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, "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", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, "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", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, "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", @@ -13749,8 +13695,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "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": { @@ -13768,7 +13714,7 @@ }, "privateEndpoint": { "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -13800,7 +13746,7 @@ "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "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" @@ -13831,7 +13777,7 @@ "privateEndpoint_privateDnsZoneGroup": { "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { @@ -13856,8 +13802,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "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." @@ -13881,7 +13827,8 @@ } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." } } }, @@ -13911,33 +13858,30 @@ } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, "resources": { "privateEndpoint": { "existing": true, "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[parameters('privateEndpointName')]" }, "privateDnsZoneGroup": { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "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]" + } + } + } + ] } } }, @@ -13998,14 +13942,15 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" }, "customDnsConfigs": { "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, "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]" @@ -14033,8 +13978,8 @@ }, "dependsOn": [ "aiFoundryAiServices", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", "virtualNetwork" ] }, @@ -14075,7 +14020,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "12454422624133946770" + "templateHash": "5741794098806372043" } }, "parameters": { @@ -14127,7 +14072,7 @@ "resources": [ { "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-06-01", + "apiVersion": "2025-10-01-preview", "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", "tags": "[parameters('tags')]", "location": "[parameters('location')]", @@ -14160,21 +14105,21 @@ "metadata": { "description": "Required. API endpoint for the AI project." }, - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')), '2025-06-01').endpoints['AI Foundry API']]" + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')), '2025-10-01-preview').endpoints['AI Foundry API']]" }, "aoaiEndpoint": { "type": "string", "metadata": { "description": "Contains AI Endpoint." }, - "value": "[if(not(empty(variables('existingOpenAIEndpoint'))), variables('existingOpenAIEndpoint'), reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName')), '2025-06-01').endpoints['OpenAI Language Model Instance API'])]" + "value": "[if(not(empty(variables('existingOpenAIEndpoint'))), variables('existingOpenAIEndpoint'), reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName')), '2025-10-01-preview').endpoints['OpenAI Language Model Instance API'])]" }, "systemAssignedMIPrincipalId": { "type": "string", "metadata": { "description": "Required. Principal ID of the AI project system-assigned managed identity." }, - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')), '2025-06-01', 'full').identity.principalId]" + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')), '2025-10-01-preview', 'full').identity.principalId]" } } } @@ -14213,7 +14158,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "5825952797275206162" + "templateHash": "3169013062799082009" } }, "parameters": { @@ -14288,14 +14233,14 @@ "metadata": { "description": "The endpoint of the existing AI Services account." }, - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName')), '2025-04-01-preview').endpoint]" + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', parameters('aiServicesName')), '2025-10-01-preview').endpoint]" }, "aiProjectPrincipalId": { "type": "string", "metadata": { "description": "The principal ID of the existing AI Project (if provided)." }, - "value": "[if(not(empty(parameters('aiProjectName'))), reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('aiProjectName')), '2025-04-01-preview', 'full').identity.principalId, '')]" + "value": "[if(not(empty(parameters('aiProjectName'))), coalesce(tryGet(tryGet(if(not(empty(parameters('aiProjectName'))), reference(resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('aiProjectName')), '2025-10-01-preview', 'full'), null()), 'identity'), 'principalId'), ''), '')]" } } } @@ -14327,12 +14272,12 @@ "value": "[parameters('enableTelemetry')]" }, "sku": "[if(parameters('enableScalability'), createObject('value', 'standard'), createObject('value', 'basic'))]", - "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", + "replicaCount": "[if(parameters('enableRedundancy'), createObject('value', 3), createObject('value', 1))]", "partitionCount": { "value": 1 }, "hostingMode": { - "value": "default" + "value": "Default" }, "semanticSearch": { "value": "free" @@ -14373,8 +14318,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "10902281417196168235" + "version": "0.39.26.7824", + "templateHash": "6207719545398489494" }, "name": "Search Services", "description": "This module deploys a Search Service." @@ -14478,122 +14423,6 @@ } } }, - "authOptionsType": { - "type": "object", - "properties": { - "aadOrApiKey": { - "type": "object", - "properties": { - "aadAuthFailureMode": { - "type": "string", - "allowedValues": [ - "http401WithBearerChallenge", - "http403" - ], - "nullable": true, - "metadata": { - "description": "Optional. Describes what response the data plane API of a search service would send for requests that failed authentication." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Indicates that either the API key or an access token from a Microsoft Entra ID tenant can be used for authentication." - } - }, - "apiKeyOnly": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Indicates that only the API key can be used for authentication." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "networkRuleSetType": { - "type": "object", - "properties": { - "bypass": { - "type": "string", - "allowedValues": [ - "AzurePortal", - "AzureServices", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Network specific rules that determine how the Azure AI Search service may be reached." - } - }, - "ipRules": { - "type": "array", - "items": { - "$ref": "#/definitions/ipRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP restriction rules that defines the inbound network(s) with allowing access to the search service endpoint. At the meantime, all other public IP networks are blocked by the firewall. These restriction rules are applied only when the 'publicNetworkAccess' of the search service is 'enabled'; otherwise, traffic over public interface is not allowed even with any public IP rules, and private endpoint connections would be the exclusive access method." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipRuleType": { - "type": "object", - "properties": { - "value": { - "type": "string", - "metadata": { - "description": "Required. Value corresponding to a single IPv4 address (eg., 123.1.2.3) or an IP range in CIDR format (eg., 123.1.2.3/24) to be allowed." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "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" - } - } - }, "_1.privateEndpointCustomDnsConfigType": { "type": "object", "properties": { @@ -14703,81 +14532,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.1" - } - } - }, "diagnosticSettingFullType": { "type": "object", "properties": { @@ -14896,7 +14650,7 @@ "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.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -14933,7 +14687,7 @@ "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" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -14961,7 +14715,7 @@ "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.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -15069,7 +14823,7 @@ } }, "lock": { - "$ref": "#/definitions/_1.lockType", + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { "description": "Optional. Specify the type of lock." @@ -15078,7 +14832,7 @@ "roleAssignments": { "type": "array", "items": { - "$ref": "#/definitions/_1.roleAssignmentType" + "$ref": "#/definitions/roleAssignmentType" }, "nullable": true, "metadata": { @@ -15181,7 +14935,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -15216,11 +14970,14 @@ } }, "authOptions": { - "$ref": "#/definitions/authOptionsType", - "nullable": true, + "type": "object", "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/authOptions" + }, "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." - } + }, + "nullable": true }, "disableLocalAuth": { "type": "bool", @@ -15236,6 +14993,17 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, + "computeType": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Confidential", + "Default" + ], + "metadata": { + "description": "Optional. The compute type of the search service." + } + }, "cmkEnforcement": { "type": "string", "defaultValue": "Unspecified", @@ -15248,12 +15016,25 @@ "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." } }, + "dataExfiltrationProtections": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Optional. A list of data exfiltration scenarios that are explicitly disallowed for the search service. Currently, the only supported value is 'All' to disable all possible data export scenarios with more fine grained controls planned for the future." + } + }, "hostingMode": { "type": "string", - "defaultValue": "default", + "defaultValue": "Default", "allowedValues": [ - "default", - "highDensity" + "Default", + "HighDensity" ], "metadata": { "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." @@ -15274,11 +15055,14 @@ } }, "networkRuleSet": { - "$ref": "#/definitions/networkRuleSetType", - "nullable": true, + "type": "object", "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Search/searchServices@2025-05-01#properties/properties/properties/networkRuleSet" + }, "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." - } + }, + "nullable": true }, "partitionCount": { "type": "int", @@ -15392,7 +15176,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Search/searchServices@2025-02-01-preview#properties/tags" + "source": "Microsoft.Search/searchServices@2025-05-01#properties/tags" }, "description": "Optional. Tags to help categorize the resource in the Azure portal." }, @@ -15426,7 +15210,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.11.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.12.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -15444,7 +15228,7 @@ }, "searchService": { "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-02-01-preview", + "apiVersion": "2025-05-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "sku": { @@ -15463,7 +15247,9 @@ "partitionCount": "[parameters('partitionCount')]", "replicaCount": "[parameters('replicaCount')]", "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", - "semanticSearch": "[parameters('semanticSearch')]" + "semanticSearch": "[parameters('semanticSearch')]", + "computeType": "[parameters('computeType')]", + "dataExfiltrationProtections": "[parameters('dataExfiltrationProtections')]" } }, "searchService_diagnosticSettings": { @@ -15549,7 +15335,7 @@ "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-searchService-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]]", @@ -15605,8 +15391,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint." @@ -15633,115 +15419,8 @@ } }, "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type of a private dns zone group." } }, "lockType": { @@ -15765,12 +15444,19 @@ "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.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -15792,6 +15478,7 @@ } }, "metadata": { + "description": "The type of a private DNS zone group configuration.", "__bicep_imported_from!": { "sourceTemplate": "private-dns-zone-group/main.bicep" } @@ -15868,7 +15555,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -15905,13 +15592,13 @@ }, "ipConfigurations": { "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, "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", @@ -15946,40 +15633,43 @@ }, "tags": { "type": "object", - "nullable": true, "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", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, "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", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, "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", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, "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", @@ -16014,8 +15704,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "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": { @@ -16033,7 +15723,7 @@ }, "privateEndpoint": { "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -16065,7 +15755,7 @@ "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "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" @@ -16096,7 +15786,7 @@ "privateEndpoint_privateDnsZoneGroup": { "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { @@ -16121,8 +15811,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "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." @@ -16146,7 +15836,8 @@ } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." } } }, @@ -16176,33 +15867,30 @@ } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, "resources": { "privateEndpoint": { "existing": true, "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[parameters('privateEndpointName')]" }, "privateDnsZoneGroup": { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "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]" + } + } + } + ] } } }, @@ -16263,14 +15951,15 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" }, "customDnsConfigs": { "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, "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]" @@ -16308,7 +15997,7 @@ "batchSize": 1 }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-searchService-SharedPrvLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { @@ -16342,8 +16031,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "557730297583881254" + "version": "0.39.26.7824", + "templateHash": "2115224445601868607" }, "name": "Search Services Private Link Resources", "description": "This module deploys a Search Service Private Link Resource." @@ -16391,12 +16080,12 @@ "searchService": { "existing": true, "type": "Microsoft.Search/searchServices", - "apiVersion": "2025-02-01-preview", + "apiVersion": "2025-05-01", "name": "[parameters('searchServiceName')]" }, "sharedPrivateLinkResource": { "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", - "apiVersion": "2025-02-01-preview", + "apiVersion": "2025-05-01", "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", "properties": { "privateLinkResourceId": "[parameters('privateLinkResourceId')]", @@ -16438,7 +16127,7 @@ "secretsExport": { "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "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]]", @@ -16452,7 +16141,7 @@ "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" }, "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-02-01-preview').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-02-01-preview').secondaryKey)), createArray()))]" + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), 'value', listAdminKeys('searchService', '2025-05-01').secondaryKey)), createArray()))]" } }, "template": { @@ -16462,8 +16151,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "7634110751636246703" + "version": "0.39.26.7824", + "templateHash": "696453183181258843" } }, "definitions": { @@ -16595,14 +16284,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[tryGet(tryGet(reference('searchService', '2025-02-01-preview', 'full'), 'identity'), 'principalId')]" + "value": "[tryGet(tryGet(reference('searchService', '2025-05-01', 'full'), 'identity'), 'principalId')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('searchService', '2025-02-01-preview', 'full').location]" + "value": "[reference('searchService', '2025-05-01', 'full').location]" }, "endpoint": { "type": "string", @@ -16642,14 +16331,14 @@ "metadata": { "description": "The primary admin API key of the search service." }, - "value": "[listAdminKeys('searchService', '2025-02-01-preview').primaryKey]" + "value": "[listAdminKeys('searchService', '2025-05-01').primaryKey]" }, "secondaryKey": { "type": "securestring", "metadata": { "description": "The secondaryKey admin API key of the search service." }, - "value": "[listAdminKeys('searchService', '2025-02-01-preview').secondaryKey]" + "value": "[listAdminKeys('searchService', '2025-05-01').secondaryKey]" } } } @@ -16747,8 +16436,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "8444048237705693390" + "version": "0.40.2.10011", + "templateHash": "9428266357530474061" }, "name": "Storage Accounts", "description": "This module deploys a Storage Account." @@ -17336,14 +17025,14 @@ "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." } }, "allowProtectedAppendWritesAll": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." } } }, @@ -18016,6 +17705,22 @@ "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." } }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, "roleAssignments": { "type": "array", "items": { @@ -19091,7 +18796,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2025-04-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.30.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.31.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -19127,7 +18832,7 @@ }, "storageAccount": { "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2025-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "extendedLocation": "[if(not(empty(parameters('extendedLocationZone'))), createObject('name', parameters('extendedLocationZone'), 'type', 'EdgeZone'), null())]", @@ -19150,7 +18855,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -19179,7 +18884,7 @@ "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", @@ -19196,7 +18901,7 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", @@ -19895,8 +19600,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "4538661605890101674" + "version": "0.40.2.10011", + "templateHash": "10458708345324133836" }, "name": "Storage Account Management Policies", "description": "This module deploys a Storage Account Management Policy." @@ -19913,7 +19618,7 @@ "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Storage/storageAccounts/managementPolicies@2024-01-01#properties/properties/properties/policy/properties/rules" + "source": "Microsoft.Storage/storageAccounts/managementPolicies@2025-06-01#properties/properties/properties/policy/properties/rules" }, "description": "Required. The Storage Account ManagementPolicies Rules." } @@ -19922,7 +19627,7 @@ "resources": [ { "type": "Microsoft.Storage/storageAccounts/managementPolicies", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", "properties": { "policy": { @@ -20007,8 +19712,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17421429164012186211" + "version": "0.40.2.10011", + "templateHash": "18432545368646748336" }, "name": "Storage Account Local Users", "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." @@ -20126,12 +19831,12 @@ "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, "localUsers": { "type": "Microsoft.Storage/storageAccounts/localUsers", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", "properties": { "hasSharedKey": "[parameters('hasSharedKey')]", @@ -20245,8 +19950,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "4804748808287128942" + "version": "0.40.2.10011", + "templateHash": "10857560398903249320" }, "name": "Storage Account blob Services", "description": "This module deploys a Storage Account Blob Service." @@ -20537,14 +20242,14 @@ "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." } }, "allowProtectedAppendWritesAll": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." } } }, @@ -20820,7 +20525,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', parameters('storageAccountName'), variables('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { "copy": [ @@ -20915,8 +20620,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "4737601268768949442" + "version": "0.40.2.10011", + "templateHash": "11027676755461897101" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container." @@ -20936,14 +20641,14 @@ "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. Defaults to false." } }, "allowProtectedAppendWritesAll": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." } } }, @@ -21166,7 +20871,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.storage-blobcontainer.{0}.{1}', replace('0.3.3', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -21209,7 +20914,7 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", @@ -21257,8 +20962,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "9416359146780945405" + "version": "0.40.2.10011", + "templateHash": "7095313291458772891" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy." @@ -21286,27 +20991,24 @@ }, "allowProtectedAppendWrites": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." } }, "allowProtectedAppendWritesAll": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive. Defaults to false." } } }, - "variables": { - "name": "default" - }, "resources": [ { "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), variables('name'))]", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", "properties": { "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", @@ -21320,14 +21022,14 @@ "metadata": { "description": "The name of the deployed immutability policy." }, - "value": "[variables('name')]" + "value": "default" }, "resourceId": { "type": "string", "metadata": { "description": "The resource ID of the deployed immutability policy." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), variables('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" }, "resourceGroupName": { "type": "string", @@ -21440,8 +21142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "8847095544204825048" + "version": "0.40.2.10011", + "templateHash": "17257177273818228540" }, "name": "Storage Account File Share Services", "description": "This module deploys a Storage Account File Share Service." @@ -21559,6 +21261,22 @@ "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." } }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, "roleAssignments": { "type": "array", "items": { @@ -21849,12 +21567,12 @@ "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, "fileServices": { "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", "properties": { "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", @@ -21869,7 +21587,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -21927,7 +21645,7 @@ "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" }, "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2024-01-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2025-06-01', 'full').kind, 'FileStorage'), if(startsWith(reference('storageAccount', '2025-06-01', 'full').sku.name, 'PremiumV2_'), null(), 'Premium'), 'TransactionOptimized'))]" }, "enabledProtocols": { "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" @@ -21938,6 +21656,12 @@ "shareQuota": { "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" }, + "provisionedBandwidthMibps": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedBandwidthMibps')]" + }, + "provisionedIops": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'provisionedIops')]" + }, "roleAssignments": { "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" }, @@ -21952,8 +21676,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "1953115828549574279" + "version": "0.40.2.10011", + "templateHash": "3816110293032807861" }, "name": "Storage Account File Shares", "description": "This module deploys a Storage Account File Share." @@ -22058,7 +21782,7 @@ }, "accessTier": { "type": "string", - "defaultValue": "TransactionOptimized", + "nullable": true, "allowedValues": [ "Premium", "Hot", @@ -22066,7 +21790,7 @@ "TransactionOptimized" ], "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized, Hot, and Cool." } }, "shareQuota": { @@ -22099,6 +21823,24 @@ "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." } }, + "provisionedBandwidthMibps": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 10340, + "metadata": { + "description": "Optional. The provisioned bandwidth of the share, in mebibytes per second. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 10340." + } + }, + "provisionedIops": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 102400, + "metadata": { + "description": "Optional. The provisioned IOPS of the share. Only applicable to FileStorage storage accounts (premium file shares). Must be between 0 and 102400." + } + }, "enableTelemetry": { "type": "bool", "defaultValue": true, @@ -22144,14 +21886,14 @@ "storageAccount::fileService": { "existing": true, "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2024-01-01", + "apiVersion": "2025-01-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "name": "[format('46d3xbcp.res.storage-fileshare.{0}.{1}', replace('0.1.3', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -22170,19 +21912,24 @@ "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-01-01", "name": "[parameters('storageAccountName')]" }, "fileShare": { "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2024-01-01", + "apiVersion": "2025-01-01", "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", "properties": { "accessTier": "[parameters('accessTier')]", "shareQuota": "[parameters('shareQuota')]", "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" - } + "enabledProtocols": "[parameters('enabledProtocols')]", + "provisionedBandwidthMibps": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedBandwidthMibps'), null())]", + "provisionedIops": "[if(equals(reference('storageAccount', '2025-01-01', 'full').kind, 'FileStorage'), parameters('provisionedIops'), null())]" + }, + "dependsOn": [ + "storageAccount" + ] }, "fileShare_roleAssignments": { "copy": { @@ -22414,8 +22161,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "762865197442503763" + "version": "0.40.2.10011", + "templateHash": "4565703002375249410" }, "name": "Storage Account Queue Services", "description": "This module deploys a Storage Account Queue Service." @@ -22760,12 +22507,12 @@ "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, "queueServices": { "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", "properties": { "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" @@ -22778,7 +22525,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}', parameters('storageAccountName'), variables('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { "copy": [ @@ -22846,8 +22593,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "2653192815476217627" + "version": "0.40.2.10011", + "templateHash": "7074748362797990420" }, "name": "Storage Account Queues", "description": "This module deploys a Storage Account Queue." @@ -22992,18 +22739,18 @@ "storageAccount::queueServices": { "existing": true, "type": "Microsoft.Storage/storageAccounts/queueServices", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" }, "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, "queue": { "type": "Microsoft.Storage/storageAccounts/queueServices/queues", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", "properties": { "metadata": "[parameters('metadata')]" @@ -23016,7 +22763,7 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}/queues/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", @@ -23119,8 +22866,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "17140438874562378925" + "version": "0.40.2.10011", + "templateHash": "6375163985707233003" }, "name": "Storage Account Table Services", "description": "This module deploys a Storage Account Table Service." @@ -23455,12 +23202,12 @@ "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, "tableServices": { "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", "properties": { "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" @@ -23473,7 +23220,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}', parameters('storageAccountName'), variables('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", "properties": { "copy": [ @@ -23538,8 +23285,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "11466809443516053137" + "version": "0.40.2.10011", + "templateHash": "5944147787326354061" }, "name": "Storage Account Table", "description": "This module deploys a Storage Account Table." @@ -23672,18 +23419,18 @@ "storageAccount::tableServices": { "existing": true, "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" }, "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[parameters('storageAccountName')]" }, "table": { "type": "Microsoft.Storage/storageAccounts/tableServices/tables", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" }, "table_roleAssignments": { @@ -23693,7 +23440,7 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}/tables/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "scope": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", @@ -23782,7 +23529,7 @@ "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('storageAccount', '2025-01-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-01-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-01-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-01-01').keys[1].value, environment().suffixes.storage))), createArray()))]" + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('storageAccount', '2025-06-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage))), createArray()))]" } }, "template": { @@ -23792,8 +23539,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "13614544361780789643" + "version": "0.40.2.10011", + "templateHash": "16028661694229002815" } }, "definitions": { @@ -23946,8 +23693,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "3528396711847214833" + "version": "0.40.2.10011", + "templateHash": "10883422529455341146" }, "name": "Storage Account Object Replication Policy", "description": "This module deploys a Storage Account Object Replication Policy for both the source account and destination account." @@ -24100,8 +23847,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "4325417308313318683" + "version": "0.40.2.10011", + "templateHash": "28895254110549746" }, "name": "Storage Account Object Replication Policy", "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." @@ -24317,8 +24064,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.39.26.7824", - "templateHash": "4325417308313318683" + "version": "0.40.2.10011", + "templateHash": "28895254110549746" }, "name": "Storage Account Object Replication Policy", "description": "This module deploys a Storage Account Object Replication Policy for a provided storage account." @@ -24562,14 +24309,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[tryGet(tryGet(reference('storageAccount', '2025-01-01', 'full'), 'identity'), 'principalId')]" + "value": "[tryGet(tryGet(reference('storageAccount', '2025-06-01', 'full'), 'identity'), 'principalId')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('storageAccount', '2025-01-01', 'full').location]" + "value": "[reference('storageAccount', '2025-06-01', 'full').location]" }, "serviceEndpoints": { "type": "object", @@ -24609,28 +24356,28 @@ "metadata": { "description": "The primary access key of the storage account." }, - "value": "[listKeys('storageAccount', '2025-01-01').keys[0].value]" + "value": "[listKeys('storageAccount', '2025-06-01').keys[0].value]" }, "secondaryAccessKey": { "type": "securestring", "metadata": { "description": "The secondary access key of the storage account." }, - "value": "[listKeys('storageAccount', '2025-01-01').keys[1].value]" + "value": "[listKeys('storageAccount', '2025-06-01').keys[1].value]" }, "primaryConnectionString": { "type": "securestring", "metadata": { "description": "The primary connection string of the storage account." }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-01-01').keys[0].value, environment().suffixes.storage)]" + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)]" }, "secondaryConnectionString": { "type": "securestring", "metadata": { "description": "The secondary connection string of the storage account." }, - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-01-01').keys[1].value, environment().suffixes.storage)]" + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys('storageAccount', '2025-06-01').keys[1].value, environment().suffixes.storage)]" } } } @@ -30621,9 +30368,7 @@ }, "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''))))), createObject('value', null()))]", "skuName": "[if(or(parameters('enableScalability'), parameters('enableRedundancy')), createObject('value', 'P1v3'), createObject('value', 'B1'))]", - "skuCapacity": { - "value": 1 - }, + "skuCapacity": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', 1))]", "zoneRedundant": "[if(parameters('enableRedundancy'), createObject('value', true()), createObject('value', false()))]" }, "template": { @@ -30633,8 +30378,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.177.2456", - "templateHash": "16945786131371363466" + "version": "0.40.2.10011", + "templateHash": "17925345736511474747" }, "name": "App Service Plan", "description": "This module deploys an App Service Plan." @@ -30725,7 +30470,7 @@ "metadata": { "description": "An AVM-aligned type for a diagnostic setting. To be used if only 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" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -30762,7 +30507,35 @@ "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" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "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.1" } } }, @@ -30837,7 +30610,7 @@ "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" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -30851,6 +30624,13 @@ "description": "Required. Name of the app service plan." } }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, "skuName": { "type": "string", "defaultValue": "P1v3", @@ -30866,75 +30646,82 @@ "description": "Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, "kind": { "type": "string", - "defaultValue": "app", - "allowedValues": [ - "app", - "elastic", - "functionapp", - "windows", - "linux" - ], "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/kind" + }, "description": "Optional. Kind of server OS." - } + }, + "defaultValue": "app" }, "reserved": { "type": "bool", - "defaultValue": "[equals(parameters('kind'), 'linux')]", "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/reserved" + }, "description": "Conditional. Defaults to false when creating Windows/app App Service Plan. Required if creating a Linux App Service Plan and must be set to true." - } + }, + "defaultValue": "[equals(parameters('kind'), 'linux')]" }, "appServiceEnvironmentResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The Resource ID of the App Service Environment to use for the App Service Plan." } }, "workerTierName": { "type": "string", - "defaultValue": "", "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/workerTierName" + }, "description": "Optional. Target worker tier assigned to the App Service plan." - } + }, + "nullable": true }, "perSiteScaling": { "type": "bool", - "defaultValue": false, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/perSiteScaling" + }, "description": "Optional. If true, apps assigned to this App Service plan can be scaled independently. If false, apps assigned to this App Service plan will scale to all instances of the plan." - } + }, + "defaultValue": false }, "elasticScaleEnabled": { "type": "bool", - "defaultValue": "[greater(parameters('maximumElasticWorkerCount'), 1)]", "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/elasticScaleEnabled" + }, "description": "Optional. Enable/Disable ElasticScaleEnabled App Service Plan." - } + }, + "defaultValue": "[greater(parameters('maximumElasticWorkerCount'), 1)]" }, "maximumElasticWorkerCount": { "type": "int", - "defaultValue": 1, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/maximumElasticWorkerCount" + }, "description": "Optional. Maximum number of total workers allowed for this ElasticScaleEnabled App Service Plan." - } + }, + "defaultValue": 1 }, "targetWorkerCount": { "type": "int", - "defaultValue": 0, "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/targetWorkerCount" + }, "description": "Optional. Scaling worker count." - } + }, + "defaultValue": 0 }, "targetWorkerSize": { "type": "int", @@ -30950,9 +30737,96 @@ }, "zoneRedundant": { "type": "bool", - "defaultValue": "[if(or(startsWith(parameters('skuName'), 'P'), startsWith(parameters('skuName'), 'EP')), true(), false())]", "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/zoneRedundant" + }, "description": "Optional. Zone Redundant server farms can only be used on Premium or ElasticPremium SKU tiers within ZRS Supported regions (https://learn.microsoft.com/en-us/azure/storage/common/redundancy-regions-zrs)." + }, + "defaultValue": "[if(or(startsWith(parameters('skuName'), 'P'), startsWith(parameters('skuName'), 'EP')), true(), false())]" + }, + "hyperV": { + "type": "bool", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/hyperV" + }, + "description": "Optional. If Hyper-V container app service plan true, false otherwise." + }, + "nullable": true + }, + "virtualNetworkSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the subnet to integrate the App Service Plan with for VNet integration." + } + }, + "isCustomMode": { + "type": "bool", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/isCustomMode" + }, + "description": "Optional. Set to true to enable Managed Instance custom mode. Required for App Service Managed Instance plans." + }, + "defaultValue": false + }, + "rdpEnabled": { + "type": "bool", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/rdpEnabled" + }, + "description": "Optional. Whether RDP is enabled for Managed Instance plans. Only applicable when isCustomMode is true. Requires a Bastion host deployed in the VNet." + }, + "nullable": true + }, + "installScripts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/installScripts" + }, + "description": "Optional. A list of install scripts for Managed Instance plans. Only applicable when isCustomMode is true." + }, + "nullable": true + }, + "planDefaultIdentity": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/planDefaultIdentity" + }, + "description": "Optional. The default identity configuration for Managed Instance plans. Only applicable when isCustomMode is true." + }, + "nullable": true + }, + "registryAdapters": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/registryAdapters" + }, + "description": "Optional. A list of registry adapters for Managed Instance plans. Only applicable when isCustomMode is true." + }, + "nullable": true + }, + "storageMounts": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/properties/properties/storageMounts" + }, + "description": "Optional. A list of storage mounts for Managed Instance plans. Only applicable when isCustomMode is true." + }, + "nullable": true + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." } }, "lock": { @@ -30976,19 +30850,12 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Web/serverfarms@2024-11-01#properties/tags" + "source": "Microsoft.Web/serverfarms@2025-03-01#properties/tags" }, "description": "Optional. Tags of the resource." }, "nullable": true }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, "diagnosticSettings": { "type": "array", "items": { @@ -30998,6 +30865,13 @@ "metadata": { "description": "Optional. The diagnostic settings of the service." } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } } }, "variables": { @@ -31016,14 +30890,16 @@ "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", "Web Plan Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2cc479cb-7b4d-49a8-b449-8c00fd0f0a4b')]", "Website Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'de139f84-1756-47ae-9be6-808fbbe84772')]" - } + }, + "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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.web-serverfarm.{0}.{1}', replace('0.5.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.web-serverfarm.{0}.{1}', replace('0.7.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -31041,22 +30917,31 @@ }, "appServicePlan": { "type": "Microsoft.Web/serverfarms", - "apiVersion": "2024-11-01", + "apiVersion": "2025-03-01", "name": "[parameters('name')]", "kind": "[parameters('kind')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", "sku": "[if(equals(parameters('skuName'), 'FC1'), createObject('name', parameters('skuName'), 'tier', 'FlexConsumption'), createObject('name', parameters('skuName'), 'capacity', parameters('skuCapacity')))]", "properties": { "workerTierName": "[parameters('workerTierName')]", - "hostingEnvironmentProfile": "[if(not(empty(parameters('appServiceEnvironmentResourceId'))), createObject('id', parameters('appServiceEnvironmentResourceId')), null())]", + "hostingEnvironmentProfile": "[if(not(equals(parameters('appServiceEnvironmentResourceId'), null())), createObject('id', parameters('appServiceEnvironmentResourceId')), null())]", "perSiteScaling": "[parameters('perSiteScaling')]", "maximumElasticWorkerCount": "[parameters('maximumElasticWorkerCount')]", "elasticScaleEnabled": "[parameters('elasticScaleEnabled')]", "reserved": "[parameters('reserved')]", "targetWorkerCount": "[parameters('targetWorkerCount')]", "targetWorkerSizeId": "[parameters('targetWorkerSize')]", - "zoneRedundant": "[parameters('zoneRedundant')]" + "zoneRedundant": "[parameters('zoneRedundant')]", + "hyperV": "[parameters('hyperV')]", + "isCustomMode": "[parameters('isCustomMode')]", + "network": "[if(not(equals(parameters('virtualNetworkSubnetId'), null())), createObject('virtualNetworkSubnetId', parameters('virtualNetworkSubnetId')), null())]", + "rdpEnabled": "[if(parameters('isCustomMode'), parameters('rdpEnabled'), null())]", + "installScripts": "[if(parameters('isCustomMode'), parameters('installScripts'), null())]", + "planDefaultIdentity": "[if(parameters('isCustomMode'), parameters('planDefaultIdentity'), null())]", + "registryAdapters": "[if(parameters('isCustomMode'), parameters('registryAdapters'), null())]", + "storageMounts": "[if(parameters('isCustomMode'), parameters('storageMounts'), null())]" } }, "appServicePlan_diagnosticSettings": { @@ -31066,7 +30951,7 @@ }, "type": "Microsoft.Insights/diagnosticSettings", "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Web/serverfarms', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ @@ -31095,7 +30980,7 @@ "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", "type": "Microsoft.Authorization/locks", "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Web/serverfarms', parameters('name'))]", "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", @@ -31112,7 +30997,7 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", + "scope": "[resourceId('Microsoft.Web/serverfarms', parameters('name'))]", "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Web/serverfarms', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", @@ -31155,7 +31040,15 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('appServicePlan', '2024-11-01', 'full').location]" + "value": "[reference('appServicePlan', '2025-03-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('appServicePlan', '2025-03-01', 'full'), 'identity'), 'principalId')]" } } } @@ -31211,6 +31104,9 @@ "enableMonitoring": { "value": "[parameters('enableMonitoring')]" }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), if(parameters('enableMonitoring'), reference('logAnalyticsWorkspace').outputs.resourceId.value, ''))))), createObject('value', null()))]", "vnetRouteAllEnabled": { "value": "[parameters('enablePrivateNetworking')]" @@ -31230,7 +31126,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "4220244191786935721" + "templateHash": "12090979410672091248" } }, "definitions": { @@ -31898,6 +31794,13 @@ "description": "Optional. Enable monitoring and logging configuration." } }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, "virtualNetworkSubnetId": { "type": "string", "nullable": true, @@ -31937,7 +31840,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Web/sites@2024-04-01#properties/properties/properties/siteConfig" + "source": "Microsoft.Web/sites@2025-03-01#properties/properties/properties/siteConfig" }, "description": "Optional. The site config object." }, @@ -31961,7 +31864,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Web/sites@2024-04-01#properties/properties/properties/functionAppConfig" + "source": "Microsoft.Web/sites@2025-03-01#properties/properties/properties/functionAppConfig" }, "description": "Optional. The Function App configuration object." }, @@ -32024,7 +31927,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Web/sites@2024-04-01#properties/properties/properties/cloningInfo" + "source": "Microsoft.Web/sites@2025-03-01#properties/properties/properties/cloningInfo" }, "description": "Optional. If specified during app creation, the app is cloned from a source app." }, @@ -32055,7 +31958,7 @@ "type": "array", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Web/sites@2024-04-01#properties/properties/properties/hostNameSslStates" + "source": "Microsoft.Web/sites@2025-03-01#properties/properties/properties/hostNameSslStates" }, "description": "Optional. Hostname SSL states are used to manage the SSL bindings for app's hostnames." }, @@ -32104,7 +32007,7 @@ "type": "object", "metadata": { "__bicep_resource_derived_type!": { - "source": "Microsoft.Web/sites@2024-04-01#properties/properties/properties/dnsConfiguration" + "source": "Microsoft.Web/sites@2025-03-01#properties/properties/properties/dnsConfiguration" }, "description": "Optional. Property to configure various DNS related settings for a site." }, @@ -32126,12 +32029,13 @@ }, "variables": { "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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "mergedSiteConfig": "[union(parameters('siteConfig'), createObject('vnetRouteAllEnabled', parameters('vnetRouteAllEnabled'), 'vnetImagePullEnabled', parameters('vnetImagePullEnabled'), 'vnetContentShareEnabled', parameters('vnetContentShareEnabled')))]" }, "resources": { "app": { "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", + "apiVersion": "2025-03-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -32146,7 +32050,7 @@ "storageAccountRequired": "[parameters('storageAccountRequired')]", "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", - "siteConfig": "[parameters('siteConfig')]", + "siteConfig": "[variables('mergedSiteConfig')]", "functionAppConfig": "[parameters('functionAppConfig')]", "clientCertEnabled": "[parameters('clientCertEnabled')]", "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", @@ -32159,9 +32063,6 @@ "hyperV": "[parameters('hyperV')]", "redundancyMode": "[parameters('redundancyMode')]", "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "vnetContentShareEnabled": "[parameters('vnetContentShareEnabled')]", - "vnetImagePullEnabled": "[parameters('vnetImagePullEnabled')]", - "vnetRouteAllEnabled": "[parameters('vnetRouteAllEnabled')]", "scmSiteAlsoStopped": "[parameters('scmSiteAlsoStopped')]", "endToEndEncryptionEnabled": "[parameters('e2eEncryptionEnabled')]", "dnsConfiguration": "[parameters('dnsConfiguration')]", @@ -32254,7 +32155,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "11071988482502090044" + "templateHash": "16113982201888016203" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting." @@ -32352,7 +32253,7 @@ "condition": "[not(empty(parameters('storageAccountResourceId')))]", "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2024-01-01", + "apiVersion": "2025-06-01", "subscriptionId": "[split(parameters('storageAccountResourceId'), '/')[2]]", "resourceGroup": "[split(parameters('storageAccountResourceId'), '/')[4]]", "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" @@ -32360,14 +32261,14 @@ "app": { "existing": true, "type": "Microsoft.Web/sites", - "apiVersion": "2023-12-01", + "apiVersion": "2025-03-01", "name": "[parameters('appName')]" }, "config": { "type": "Microsoft.Web/sites/config", - "apiVersion": "2024-04-01", + "apiVersion": "2025-03-01", "name": "[format('{0}/{1}', parameters('appName'), parameters('name'))]", - "properties": "[union(parameters('properties'), parameters('currentAppSettings'), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(parameters('storageAccountResourceId'), '/')), listKeys('storageAccount', '2024-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), createObject('AzureWebJobsStorage__accountName', last(split(parameters('storageAccountResourceId'), '/')), 'AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob, 'AzureWebJobsStorage__queueServiceUri', reference('storageAccount').primaryEndpoints.queue, 'AzureWebJobsStorage__tableServiceUri', reference('storageAccount').primaryEndpoints.table), createObject())), if(not(empty(parameters('applicationInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('applicationInsights').ConnectionString), createObject()), variables('loggingProperties'))]", + "properties": "[union(parameters('properties'), parameters('currentAppSettings'), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(parameters('storageAccountResourceId'), '/')), listKeys('storageAccount', '2025-06-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), createObject('AzureWebJobsStorage__accountName', last(split(parameters('storageAccountResourceId'), '/')), 'AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob, 'AzureWebJobsStorage__queueServiceUri', reference('storageAccount').primaryEndpoints.queue, 'AzureWebJobsStorage__tableServiceUri', reference('storageAccount').primaryEndpoints.table), createObject())), if(not(empty(parameters('applicationInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('applicationInsights').ConnectionString), createObject()), variables('loggingProperties'))]", "dependsOn": [ "applicationInsights", "storageAccount" @@ -32428,7 +32329,7 @@ "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, "enableTelemetry": { - "value": false + "value": "[parameters('enableTelemetry')]" }, "location": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" @@ -32465,8 +32366,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint." @@ -32493,115 +32394,8 @@ } }, "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type of a private dns zone group." } }, "lockType": { @@ -32625,12 +32419,19 @@ "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.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } }, @@ -32652,6 +32453,7 @@ } }, "metadata": { + "description": "The type of a private DNS zone group configuration.", "__bicep_imported_from!": { "sourceTemplate": "private-dns-zone-group/main.bicep" } @@ -32728,7 +32530,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -32765,13 +32567,13 @@ }, "ipConfigurations": { "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, "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", @@ -32806,40 +32608,43 @@ }, "tags": { "type": "object", - "nullable": true, "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", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, "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", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, "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", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, "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", @@ -32874,8 +32679,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "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": { @@ -32893,7 +32698,7 @@ }, "privateEndpoint": { "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -32925,7 +32730,7 @@ "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", "properties": { "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "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" @@ -32956,7 +32761,7 @@ "privateEndpoint_privateDnsZoneGroup": { "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { @@ -32981,8 +32786,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13997305779829540948" + "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." @@ -33006,7 +32811,8 @@ } }, "metadata": { - "__bicep_export!": true + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." } } }, @@ -33036,33 +32842,30 @@ } } }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, "resources": { "privateEndpoint": { "existing": true, "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[parameters('privateEndpointName')]" }, "privateDnsZoneGroup": { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", + "apiVersion": "2024-10-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + "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]" + } + } + } + ] } } }, @@ -33123,14 +32926,15 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + "value": "[reference('privateEndpoint', '2024-10-01', 'full').location]" }, "customDnsConfigs": { "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, "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]" @@ -33189,14 +32993,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[tryGet(tryGet(reference('app', '2024-04-01', 'full'), 'identity'), 'principalId')]" + "value": "[tryGet(tryGet(reference('app', '2025-03-01', 'full'), 'identity'), 'principalId')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('app', '2024-04-01', 'full').location]" + "value": "[reference('app', '2025-03-01', 'full').location]" }, "defaultHostname": { "type": "string", @@ -33262,9 +33066,6 @@ "value": 8000 }, "subnetResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('virtualNetwork').outputs.aciSubnetResourceId.value), createObject('value', ''))]", - "registryServer": { - "value": "[format('{0}.azurecr.io', variables('acrResourceName'))]" - }, "userAssignedIdentityResourceId": { "value": "[reference('userAssignedIdentity').outputs.resourceId.value]" }, @@ -33375,7 +33176,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "5126970369332146090" + "templateHash": "10099291518724984652" } }, "parameters": { @@ -33445,12 +33246,6 @@ "description": "Optional. Enable telemetry." } }, - "registryServer": { - "type": "string", - "metadata": { - "description": "Required. Container registry server." - } - }, "userAssignedIdentityResourceId": { "type": "string", "defaultValue": "", @@ -33479,7 +33274,7 @@ }, { "type": "Microsoft.ContainerInstance/containerGroups", - "apiVersion": "2023-05-01", + "apiVersion": "2025-09-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -33547,14 +33342,14 @@ "metadata": { "description": "The IP address of the container (private or public depending on mode)." }, - "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups', parameters('name')), '2023-05-01').ipAddress.ip]" + "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups', parameters('name')), '2025-09-01').ipAddress.ip]" }, "fqdn": { "type": "string", "metadata": { "description": "The FQDN of the container (only available for public mode)." }, - "value": "[if(variables('isPrivateNetworking'), '', reference(resourceId('Microsoft.ContainerInstance/containerGroups', parameters('name')), '2023-05-01').ipAddress.fqdn)]" + "value": "[if(variables('isPrivateNetworking'), '', reference(resourceId('Microsoft.ContainerInstance/containerGroups', parameters('name')), '2025-09-01').ipAddress.fqdn)]" } } } diff --git a/content-gen/infra/modules/ai-project.bicep b/content-gen/infra/modules/ai-project.bicep index 6809b0aac..ee6eeeec5 100644 --- a/content-gen/infra/modules/ai-project.bicep +++ b/content-gen/infra/modules/ai-project.bicep @@ -22,11 +22,11 @@ var existingOpenAIEndpoint = useExistingAiFoundryAiProject : '' // Reference to cognitive service in current resource group for new projects -resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2025-06-01' existing = { +resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2025-10-01-preview' existing = { name: aiServicesName } -resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-06-01' = { +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-10-01-preview' = { parent: cogServiceReference name: name tags: tags diff --git a/content-gen/infra/modules/container-instance.bicep b/content-gen/infra/modules/container-instance.bicep index 53f7267db..9d3a837bd 100644 --- a/content-gen/infra/modules/container-instance.bicep +++ b/content-gen/infra/modules/container-instance.bicep @@ -31,9 +31,6 @@ param environmentVariables array @description('Optional. Enable telemetry.') param enableTelemetry bool = true -@description('Required. Container registry server.') -param registryServer string - @description('Optional. User-assigned managed identity resource ID for ACR pull.') param userAssignedIdentityResourceId string = '' @@ -56,7 +53,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource containerGroup 'Microsoft.ContainerInstance/containerGroups@2023-05-01' = { +resource containerGroup 'Microsoft.ContainerInstance/containerGroups@2025-09-01' = { name: name location: location tags: tags diff --git a/content-gen/infra/modules/deploy_foundry_role_assignment.bicep b/content-gen/infra/modules/deploy_foundry_role_assignment.bicep index 3121ca932..041e60d5f 100644 --- a/content-gen/infra/modules/deploy_foundry_role_assignment.bicep +++ b/content-gen/infra/modules/deploy_foundry_role_assignment.bicep @@ -36,12 +36,12 @@ resource cognitiveServicesOpenAiUserRole 'Microsoft.Authorization/roleDefinition // ========== Existing Resources ========== // // Reference the existing AI Services account -resource existingAiServices 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = { +resource existingAiServices 'Microsoft.CognitiveServices/accounts@2025-10-01-preview' existing = { name: aiServicesName } // Reference the existing AI Project (if provided) -resource existingAiProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' existing = if (!empty(aiProjectName)) { +resource existingAiProject 'Microsoft.CognitiveServices/accounts/projects@2025-10-01-preview' existing = if (!empty(aiProjectName)) { name: aiProjectName parent: existingAiServices } @@ -81,4 +81,4 @@ output aiServicesResourceId string = existingAiServices.id output aiServicesEndpoint string = existingAiServices.properties.endpoint @description('The principal ID of the existing AI Project (if provided).') -output aiProjectPrincipalId string = !empty(aiProjectName) ? existingAiProject.identity.principalId : '' +output aiProjectPrincipalId string = !empty(aiProjectName) ? existingAiProject.?identity.?principalId ?? '' : '' diff --git a/content-gen/infra/modules/web-sites.bicep b/content-gen/infra/modules/web-sites.bicep index 9f78af838..17a63ea77 100644 --- a/content-gen/infra/modules/web-sites.bicep +++ b/content-gen/infra/modules/web-sites.bicep @@ -49,6 +49,9 @@ param storageAccountRequired bool = false @description('Optional. Enable monitoring and logging configuration.') param enableMonitoring bool = false +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + @description('Optional. Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration.') param virtualNetworkSubnetId string? @@ -65,7 +68,7 @@ param vnetRouteAllEnabled bool = false param scmSiteAlsoStopped bool = false @description('Optional. The site config object.') -param siteConfig resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.siteConfig = { +param siteConfig resourceInput<'Microsoft.Web/sites@2025-03-01'>.properties.siteConfig = { alwaysOn: true minTlsVersion: '1.2' ftpsState: 'FtpsOnly' @@ -75,7 +78,7 @@ param siteConfig resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.site param configs appSettingsConfigType[]? @description('Optional. The Function App configuration object.') -param functionAppConfig resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.functionAppConfig? +param functionAppConfig resourceInput<'Microsoft.Web/sites@2025-03-01'>.properties.functionAppConfig? import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' @description('Optional. Configuration details for private endpoints.') @@ -103,7 +106,7 @@ param clientCertExclusionPaths string? param clientCertMode string = 'Optional' @description('Optional. If specified during app creation, the app is cloned from a source app.') -param cloningInfo resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.cloningInfo? +param cloningInfo resourceInput<'Microsoft.Web/sites@2025-03-01'>.properties.cloningInfo? @description('Optional. Size of the function container.') param containerSize int? @@ -115,7 +118,7 @@ param dailyMemoryTimeQuota int? param enabled bool = true @description('Optional. Hostname SSL states are used to manage the SSL bindings for app\'s hostnames.') -param hostNameSslStates resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.hostNameSslStates? +param hostNameSslStates resourceInput<'Microsoft.Web/sites@2025-03-01'>.properties.hostNameSslStates? @description('Optional. Hyper-V sandbox.') param hyperV bool = false @@ -141,7 +144,7 @@ param publicNetworkAccess string? param e2eEncryptionEnabled bool? @description('Optional. Property to configure various DNS related settings for a site.') -param dnsConfiguration resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.dnsConfiguration? +param dnsConfiguration resourceInput<'Microsoft.Web/sites@2025-03-01'>.properties.dnsConfiguration? @description('Optional. Specifies the scope of uniqueness for the default hostname during resource creation.') @allowed([ @@ -167,7 +170,14 @@ var identity = !empty(managedIdentities) } : null -resource app 'Microsoft.Web/sites@2024-04-01' = { +// Merge vnet properties into siteConfig (these properties moved from top-level to siteConfig in newer API versions) +var mergedSiteConfig = union(siteConfig, { + vnetRouteAllEnabled: vnetRouteAllEnabled + vnetImagePullEnabled: vnetImagePullEnabled + vnetContentShareEnabled: vnetContentShareEnabled +}) + +resource app 'Microsoft.Web/sites@2025-03-01' = { name: name location: location kind: kind @@ -186,7 +196,7 @@ resource app 'Microsoft.Web/sites@2024-04-01' = { storageAccountRequired: storageAccountRequired keyVaultReferenceIdentity: keyVaultAccessIdentityResourceId virtualNetworkSubnetId: virtualNetworkSubnetId - siteConfig: siteConfig + siteConfig: mergedSiteConfig functionAppConfig: functionAppConfig clientCertEnabled: clientCertEnabled clientCertExclusionPaths: clientCertExclusionPaths @@ -201,9 +211,6 @@ resource app 'Microsoft.Web/sites@2024-04-01' = { publicNetworkAccess: !empty(publicNetworkAccess) ? any(publicNetworkAccess) : (!empty(privateEndpoints) ? 'Disabled' : 'Enabled') - vnetContentShareEnabled: vnetContentShareEnabled - vnetImagePullEnabled: vnetImagePullEnabled - vnetRouteAllEnabled: vnetRouteAllEnabled scmSiteAlsoStopped: scmSiteAlsoStopped endToEndEncryptionEnabled: e2eEncryptionEnabled dnsConfiguration: dnsConfiguration @@ -259,7 +266,7 @@ resource app_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-0 } ] -module app_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.11.0' = [ +module app_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.11.1' = [ for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-app-PrivateEndpoint-${index}' scope: resourceGroup( @@ -296,7 +303,7 @@ module app_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.11.0' ] : null subnetResourceId: privateEndpoint.subnetResourceId - enableTelemetry: false + enableTelemetry: enableTelemetry location: privateEndpoint.?location ?? reference( split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', diff --git a/content-gen/infra/modules/web-sites.config.bicep b/content-gen/infra/modules/web-sites.config.bicep index 34ff9e4c9..91d935d6d 100644 --- a/content-gen/infra/modules/web-sites.config.bicep +++ b/content-gen/infra/modules/web-sites.config.bicep @@ -96,16 +96,16 @@ resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing scope: resourceGroup(split(applicationInsightResourceId!, '/')[2], split(applicationInsightResourceId!, '/')[4]) } -resource storageAccount 'Microsoft.Storage/storageAccounts@2024-01-01' existing = if (!empty(storageAccountResourceId)) { +resource storageAccount 'Microsoft.Storage/storageAccounts@2025-06-01' existing = if (!empty(storageAccountResourceId)) { name: last(split(storageAccountResourceId!, '/')) scope: resourceGroup(split(storageAccountResourceId!, '/')[2], split(storageAccountResourceId!, '/')[4]) } -resource app 'Microsoft.Web/sites@2023-12-01' existing = { +resource app 'Microsoft.Web/sites@2025-03-01' existing = { name: appName } -resource config 'Microsoft.Web/sites/config@2024-04-01' = { +resource config 'Microsoft.Web/sites/config@2025-03-01' = { parent: app #disable-next-line BCP225 name: name diff --git a/content-gen/scripts/post_deploy.py b/content-gen/scripts/post_deploy.py index 12b0d3a75..5eaaa3ac4 100644 --- a/content-gen/scripts/post_deploy.py +++ b/content-gen/scripts/post_deploy.py @@ -36,11 +36,13 @@ import argparse import asyncio import base64 +import json import os +import subprocess import sys from dataclasses import dataclass from pathlib import Path -from typing import Dict +from typing import Dict, Optional try: import httpx @@ -103,6 +105,102 @@ def print_warning(text: str): print(f"{Colors.YELLOW}⚠ {text}{Colors.END}") +def get_values_from_az_deployment(resource_group: str) -> Optional[Dict[str, str]]: + """Get deployment output values from Azure using az CLI.""" + print_step("Getting values from Azure deployment outputs...") + + try: + # First, try to get deployment name from resource group tags + result = subprocess.run( + ["az", "group", "show", "--name", resource_group, "--query", "tags.DeploymentName", "-o", "tsv"], + capture_output=True, + text=True, + check=True, + shell=True # Required on Windows to find az.cmd + ) + deployment_name = result.stdout.strip() + + # If no tag found, try to find the most recent successful deployment + if not deployment_name or deployment_name == "None": + print_warning("No DeploymentName tag found on resource group") + print_step("Searching for most recent successful deployment...") + + result = subprocess.run( + ["az", "deployment", "group", "list", + "--resource-group", resource_group, + "--query", "[?properties.provisioningState=='Succeeded'] | sort_by(@, &properties.timestamp) | [-1].name", + "-o", "tsv"], + capture_output=True, + text=True, + check=True, + shell=True + ) + deployment_name = result.stdout.strip() + + if not deployment_name or deployment_name == "None": + print_warning("No successful deployments found in resource group") + return None + + print(f" Found deployment: {deployment_name}") + else: + print(f" Deployment Name (from tag): {deployment_name}") + + # Get deployment outputs + print_step("Fetching deployment outputs...") + result = subprocess.run( + ["az", "deployment", "group", "show", + "--name", deployment_name, + "--resource-group", resource_group, + "--query", "properties.outputs", + "-o", "json"], + capture_output=True, + text=True, + check=True, + shell=True # Required on Windows to find az.cmd + ) + + outputs = json.loads(result.stdout) + + # Extract values from deployment outputs + # The outputs are in format: {"keyName": {"type": "String", "value": "actual-value"}} + def extract_value(key: str, fallback_key: str = "") -> str: + """Extract value from deployment outputs, trying fallback key if primary not found.""" + if key in outputs and "value" in outputs[key]: + return outputs[key]["value"] + if fallback_key and fallback_key in outputs and "value" in outputs[fallback_key]: + return outputs[fallback_key]["value"] + return "" + + values = { + "app_service": extract_value("appServiceName", "APP_SERVICE_NAME"), + "storage_account": extract_value("azureBlobAccountName", "AZURE_BLOB_ACCOUNT_NAME"), + "cosmos_account": extract_value("cosmosDbAccountName", "COSMOSDB_ACCOUNT_NAME"), + "search_service": extract_value("aiSearchServiceName", "AI_SEARCH_SERVICE_NAME"), + } + + # Filter out empty values + values = {k: v for k, v in values.items() if v} + + if values: + print_success(f"Retrieved {len(values)} values from deployment outputs") + for k, v in values.items(): + print(f" {k}: {v}") + else: + print_warning("No matching values found in deployment outputs") + + return values + + except subprocess.CalledProcessError as e: + print_warning(f"Failed to query Azure deployment: {e.stderr if e.stderr else str(e)}") + return None + except json.JSONDecodeError as e: + print_warning(f"Failed to parse deployment outputs: {e}") + return None + except Exception as e: + print_warning(f"Error getting deployment values: {e}") + return None + + def discover_resources(resource_group: str, app_name: str, storage_account: str, cosmos_account: str, search_service: str, api_key: str = "") -> ResourceConfig: """Build resource configuration from provided values (no Azure CLI required).""" print_step("Configuring Azure resources...") @@ -144,7 +242,10 @@ async def check_admin_api_health(config: ResourceConfig) -> bool: async with httpx.AsyncClient(timeout=30.0) as client: try: - response = await client.get(f"{config.app_url}/api/admin/health") + response = await client.get( + f"{config.app_url}/api/admin/health", + headers=get_api_headers(config) + ) if response.status_code == 200: data = response.json() print_success(f"Admin API healthy (API key required: {data.get('api_key_required', False)})") @@ -506,7 +607,7 @@ async def main(): args = parser.parse_args() - # Get values from args or environment variables (args take precedence) + # Priority 1: Command line arguments resource_group = args.resource_group or os.environ.get("RESOURCE_GROUP_NAME", "") app_name = args.app_name or os.environ.get("APP_SERVICE_NAME", "") storage_account = args.storage_account or os.environ.get("AZURE_BLOB_ACCOUNT_NAME", "") @@ -514,9 +615,39 @@ async def main(): search_service = args.search_service or os.environ.get("AI_SEARCH_SERVICE_NAME", "") api_key = args.api_key or os.environ.get("ADMIN_API_KEY", "") + # Priority 2: If resource group is provided but other values are missing, try deployment outputs + if resource_group and (not app_name or not storage_account or not cosmos_account or not search_service): + print() + deployment_values = get_values_from_az_deployment(resource_group) + if deployment_values: + # Use deployment values only for missing parameters + app_name = app_name or deployment_values.get("app_service", "") + storage_account = storage_account or deployment_values.get("storage_account", "") + cosmos_account = cosmos_account or deployment_values.get("cosmos_account", "") + search_service = search_service or deployment_values.get("search_service", "") + else: + print_warning("Could not retrieve values from deployment outputs") + # Validate required values are present - if not resource_group or not app_name or not storage_account or not cosmos_account or not search_service: - print_error("Missing required resource names. Provide via arguments or set environment variables: RESOURCE_GROUP_NAME (--resource-group), APP_SERVICE_NAME (--app-name), AZURE_BLOB_ACCOUNT_NAME (--storage-account), COSMOSDB_ACCOUNT_NAME (--cosmos-account), AI_SEARCH_SERVICE_NAME (--search-service)") + if not resource_group: + print_error("Resource group is required. Provide via --resource-group argument or RESOURCE_GROUP_NAME environment variable.") + sys.exit(1) + + if not app_name or not storage_account or not cosmos_account or not search_service: + print_error("Missing required resource names. Please provide via:") + print(" 1. Command line arguments (--app-name, --storage-account, --cosmos-account, --search-service)") + print(" 2. Environment variables (APP_SERVICE_NAME, AZURE_BLOB_ACCOUNT_NAME, COSMOSDB_ACCOUNT_NAME, AI_SEARCH_SERVICE_NAME)") + print(" 3. Azure deployment outputs (automatic if resource group has DeploymentName tag)") + print() + print("Missing values:") + if not app_name: + print(" - App Service name") + if not storage_account: + print(" - Storage Account name") + if not cosmos_account: + print(" - Cosmos DB Account name") + if not search_service: + print(" - AI Search Service name") sys.exit(1) print_header("Content Generation Solution Accelerator - Post Deployment")