From 4acbde2952e8ba956fb172896eed2e4d9368ce22 Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Wed, 9 Jul 2025 16:48:00 +0530 Subject: [PATCH 1/2] merge down for reuse aif --- infra/main.bicep | 36 +- infra/main.parameters.json | 3 + infra/modules/ai-foundry/dependencies.bicep | 479 ++++++++++++++++++ infra/modules/ai-foundry/keyVaultExport.bicep | 43 ++ infra/modules/ai-foundry/main.bicep | 462 ++++++++++++++--- infra/modules/ai-foundry/project.bicep | 73 +-- infra/samples/network_subnet_design.md | 2 +- 7 files changed, 973 insertions(+), 125 deletions(-) create mode 100644 infra/modules/ai-foundry/dependencies.bicep create mode 100644 infra/modules/ai-foundry/keyVaultExport.bicep diff --git a/infra/main.bicep b/infra/main.bicep index c275188f..f1414266 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -96,6 +96,9 @@ param imageVersion string = 'latest' @description('Version of the GPT model to deploy:') param gptModelVersion string = '2024-08-06' +@description('Use this parameter to use an existing AI project resource ID') +param azureExistingAIProjectResourceId string = '' + param existingLogAnalyticsWorkspaceId string = '' var allTags = union( @@ -221,7 +224,7 @@ module network 'modules/network.bicep' = if (enablePrivateNetworking) { } module aiServices 'modules/ai-foundry/main.bicep' = { - name: take('aiservices-${resourcesName}-deployment', 64) + name: take('avm.res.cognitive-services.account.${resourcesName}', 64) #disable-next-line no-unnecessary-dependson dependsOn: [logAnalyticsWorkspace, network] // required due to optional flags that could change dependency params: { @@ -229,8 +232,9 @@ module aiServices 'modules/ai-foundry/main.bicep' = { location: aiDeploymentsLocation sku: 'S0' kind: 'AIServices' - deployments: [modelDeployment] + deployments: [ modelDeployment ] projectName: '${abbrs.ai.aiFoundryProject}${resourcesName}' + projectDescription: '${abbrs.ai.aiFoundryProject}${resourcesName}' logAnalyticsWorkspaceResourceId: enableMonitoring ? logAnalyticsWorkspaceResourceId : '' privateNetworking: enablePrivateNetworking ? { @@ -238,6 +242,22 @@ module aiServices 'modules/ai-foundry/main.bicep' = { subnetResourceId: network.outputs.subnetPrivateEndpointsResourceId } : null + existingFoundryProjectResourceId: azureExistingAIProjectResourceId + disableLocalAuth: true //Should be set to true for WAF aligned configuration + customSubDomainName: 'ais-${resourcesName}' + apiProperties: { + //staticsEnabled: false + } + allowProjectManagement: true + managedIdentities: { + systemAssigned: true + } + publicNetworkAccess: 'Enabled' + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Allow' + } + privateEndpoints: [] roleAssignments: [ { principalId: appIdentity.outputs.principalId @@ -314,9 +334,9 @@ module keyVault 'modules/keyVault.bicep' = { : null roleAssignments: [ { - principalId: aiServices.outputs.?systemAssignedMIPrincipalId ?? '' + principalId: aiServices.outputs.?systemAssignedMIPrincipalId ?? appIdentity.outputs.principalId principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Key Vault Reader' + roleDefinitionIdOrName: 'Key Vault Administrator' } ] tags: allTags @@ -473,15 +493,15 @@ module containerAppBackend 'br/public:avm/res/app/container-app:0.17.0' = { } { name: 'AI_PROJECT_ENDPOINT' - value: aiServices.outputs.project.apiEndpoint // or equivalent + value: aiServices.outputs.aiProjectInfo.apiEndpoint // or equivalent } { name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' // This was not really used in code. - value: aiServices.outputs.project.apiEndpoint + value: aiServices.outputs.aiProjectInfo.apiEndpoint } { name: 'AZURE_AI_AGENT_PROJECT_NAME' - value: aiServices.outputs.project.name + value: aiServices.outputs.aiProjectInfo.name } { name: 'AZURE_AI_AGENT_RESOURCE_GROUP_NAME' @@ -493,7 +513,7 @@ module containerAppBackend 'br/public:avm/res/app/container-app:0.17.0' = { } { name: 'AZURE_AI_AGENT_ENDPOINT' - value: aiServices.outputs.project.apiEndpoint + value: aiServices.outputs.aiProjectInfo.apiEndpoint } { name: 'AZURE_CLIENT_ID' diff --git a/infra/main.parameters.json b/infra/main.parameters.json index 5cbe4410..099bf026 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -26,6 +26,9 @@ "existingLogAnalyticsWorkspaceId": { "value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}" }, + "azureExistingAIProjectResourceId": { + "value": "${AZURE_EXISTING_AI_PROJECT_RESOURCE_ID}" + }, "secondaryLocation": { "value": "${AZURE_ENV_COSMOS_SECONDARY_LOCATION}" }, diff --git a/infra/modules/ai-foundry/dependencies.bicep b/infra/modules/ai-foundry/dependencies.bicep new file mode 100644 index 00000000..bbeedac2 --- /dev/null +++ b/infra/modules/ai-foundry/dependencies.bicep @@ -0,0 +1,479 @@ +@description('Required. The name of Cognitive Services account.') +param name string + +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'C2' + 'C3' + 'C4' + 'F0' + 'F1' + 'S' + 'S0' + 'S1' + 'S10' + 'S2' + 'S3' + 'S4' + 'S5' + 'S6' + 'S7' + 'S8' + 'S9' +]) +param sku string = 'S0' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Array of deployments about cognitive service accounts to create.') +param deployments deploymentType[]? + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional: Name for the project which needs to be created.') +param projectName string + +@description('Optional: Description for the project which needs to be created.') +param projectDescription string + +@description('Optional: Provide the existing project resource id in case if it needs to be reused') +param azureExistingAIProjectResourceId string = '' + +var builtInRoleNames = { + 'Cognitive Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68' + ) + 'Cognitive Services Custom Vision Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3' + ) + 'Cognitive Services Custom Vision Deployment': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5c4089e1-6d96-4d2f-b296-c1bc7137275f' + ) + 'Cognitive Services Custom Vision Labeler': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '88424f51-ebe7-446f-bc41-7fa16989e96c' + ) + 'Cognitive Services Custom Vision Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '93586559-c37d-4a6b-ba08-b9f0940c2d73' + ) + 'Cognitive Services Custom Vision Trainer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b' + ) + 'Cognitive Services Data Reader (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b59867f0-fa02-499b-be73-45a86b5b3e1c' + ) + 'Cognitive Services Face Recognizer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '9894cab4-e18a-44aa-828b-cb588cd6f2d7' + ) + 'Cognitive Services Immersive Reader User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b2de6794-95db-4659-8781-7e080d3f2b9d' + ) + 'Cognitive Services Language Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f07febfe-79bc-46b1-8b37-790e26e6e498' + ) + 'Cognitive Services Language Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7628b7b8-a8b2-4cdc-b46f-e9b35248918e' + ) + 'Cognitive Services Language Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8' + ) + 'Cognitive Services LUIS Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f72c8140-2111-481c-87ff-72b910f6e3f8' + ) + 'Cognitive Services LUIS Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18e81cdc-4e98-4e29-a639-e7d10c5a6226' + ) + 'Cognitive Services LUIS Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '6322a993-d5c9-4bed-b113-e49bbea25b27' + ) + 'Cognitive Services Metrics Advisor Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'cb43c632-a144-4ec5-977c-e80c4affc34a' + ) + 'Cognitive Services Metrics Advisor User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3b20f47b-3825-43cb-8114-4bd2201156a8' + ) + 'Cognitive Services OpenAI Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a001fd3d-188f-4b5d-821b-7da978bf7442' + ) + 'Cognitive Services OpenAI User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + ) + 'Cognitive Services QnA Maker Editor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f4cc2bf9-21be-47a1-bdf1-5c5804381025' + ) + 'Cognitive Services QnA Maker Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '466ccd10-b268-4a11-b098-b4849f024126' + ) + 'Cognitive Services Speech Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0e75ca1e-0464-4b4d-8b93-68208a576181' + ) + 'Cognitive Services Speech User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2dc8367-1007-4938-bd23-fe263f013447' + ) + 'Cognitive Services User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a97b65f3-24c7-4388-baec-2e87135dc908' + ) + 'Azure AI Developer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '64702f94-c441-49e6-a78b-ef80e0188fee' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +var enableReferencedModulesTelemetry = false + +resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = { + name: name +} + +@batchSize(1) +resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/deployments@2025-04-01-preview' = [ + for (deployment, index) in (deployments ?? []): { + parent: cognitiveService + name: deployment.?name ?? '${name}-deployments' + properties: { + model: deployment.model + raiPolicyName: deployment.?raiPolicyName + versionUpgradeOption: deployment.?versionUpgradeOption + } + sku: deployment.?sku ?? { + name: sku + capacity: sku.?capacity + tier: sku.?tier + size: sku.?size + family: sku.?family + } + } +] + +resource cognitiveService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: cognitiveService +} + +resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: cognitiveService + } +] + +module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.11.0' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}' + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(cognitiveService.id, '/'))}-${privateEndpoint.?service ?? 'account'}-${index}' + properties: { + privateLinkServiceId: cognitiveService.id + groupIds: [ + privateEndpoint.?service ?? 'account' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: enableReferencedModulesTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: cognitiveService + } +] + +module secretsExport 'keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[2], + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId!, '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'accessKey1Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey1Name + value: cognitiveService.listKeys().key1 + } + ] + : [], + contains(secretsExportConfiguration!, 'accessKey2Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey2Name + value: cognitiveService.listKeys().key2 + } + ] + : [] + ) + } +} + +module aiProject 'project.bicep' = if(!empty(projectName) || !empty(azureExistingAIProjectResourceId)) { + name: take('${name}-ai-project-${projectName}-deployment', 64) + params: { + name: projectName + desc: projectDescription + aiServicesName: cognitiveService.name + location: location + tags: tags + azureExistingAIProjectResourceId: azureExistingAIProjectResourceId + } +} + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + +@description('The private endpoints of the congitive services account.') +output privateEndpoints privateEndpointOutputType[] = [ + for (pe, index) in (privateEndpoints ?? []): { + name: cognitiveService_privateEndpoints[index].outputs.name + resourceId: cognitiveService_privateEndpoints[index].outputs.resourceId + groupId: cognitiveService_privateEndpoints[index].outputs.?groupId! + customDnsConfigs: cognitiveService_privateEndpoints[index].outputs.customDnsConfigs + networkInterfaceResourceIds: cognitiveService_privateEndpoints[index].outputs.networkInterfaceResourceIds + } +] + +import { aiProjectOutputType } from './project.bicep' +output aiProjectInfo aiProjectOutputType = aiProject.outputs.aiProjectInfo + +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for the private endpoint output.') +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The type for a cognitive services account deployment.') +type deploymentType = { + @description('Optional. Specify the name of cognitive service account deployment.') + name: string? + + @description('Required. Properties of Cognitive Services account deployment model.') + model: { + @description('Required. The name of Cognitive Services account deployment model.') + name: string + + @description('Required. The format of Cognitive Services account deployment model.') + format: string + + @description('Required. The version of Cognitive Services account deployment model.') + version: string + } + + @description('Optional. The resource model definition representing SKU.') + sku: { + @description('Required. The name of the resource model definition representing SKU.') + name: string + + @description('Optional. The capacity of the resource model definition representing SKU.') + capacity: int? + + @description('Optional. The tier of the resource model definition representing SKU.') + tier: string? + + @description('Optional. The size of the resource model definition representing SKU.') + size: string? + + @description('Optional. The family of the resource model definition representing SKU.') + family: string? + }? + + @description('Optional. The name of RAI policy.') + raiPolicyName: string? + + @description('Optional. The version upgrade option.') + versionUpgradeOption: string? +} + +@export() +@description('The type for a cognitive services account endpoint.') +type endpointType = { + @description('Type of the endpoint.') + name: string? + @description('The endpoint URI.') + endpoint: string? +} + +@export() +@description('The type of the secrets exported to the provided Key Vault.') +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The name for the accessKey1 secret to create.') + accessKey1Name: string? + + @description('Optional. The name for the accessKey2 secret to create.') + accessKey2Name: string? +} diff --git a/infra/modules/ai-foundry/keyVaultExport.bicep b/infra/modules/ai-foundry/keyVaultExport.bicep new file mode 100644 index 00000000..a54cc557 --- /dev/null +++ b/infra/modules/ai-foundry/keyVaultExport.bicep @@ -0,0 +1,43 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the ecrets in.') +param keyVaultName string + +import { secretToSetType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // + +import { secretSetOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetOutputType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + secretUriWithVersion: secrets[index].properties.secretUriWithVersion + } +] diff --git a/infra/modules/ai-foundry/main.bicep b/infra/modules/ai-foundry/main.bicep index c3b9580a..89dfe2d3 100644 --- a/infra/modules/ai-foundry/main.bicep +++ b/infra/modules/ai-foundry/main.bicep @@ -60,9 +60,10 @@ param projectDescription string = projectName @description('Optional. The resource ID of the Log Analytics workspace to use for diagnostic settings.') param logAnalyticsWorkspaceResourceId string? -import { deploymentType } from 'br/public:avm/res/cognitive-services/account:0.10.2' +param existingFoundryProjectResourceId string = '' + @description('Optional. Specifies the OpenAI deployments to create.') -param deployments deploymentType[] = [] +param deployments deploymentType[]? import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' @description('Optional. Array of role assignments to create.') @@ -71,13 +72,133 @@ param roleAssignments roleAssignmentType[] = [] @description('Optional. Values to establish private networking for the AI Services resource.') param privateNetworking aiServicesPrivateNetworkingType? +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string? + +@description('Conditional. Subdomain name used for token-based authentication. Required if \'networkAcls\' or \'privateEndpoints\' are set.') +param customSubDomainName string? + +@description('Optional. A collection of rules governing the accessibility from specific network locations.') +param networkAcls object? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + @description('Optional. Tags to be applied to the resources.') param tags object = {} +@description('Optional. List of allowed FQDN.') +param allowedFqdnList array? + +@description('Optional. The API properties for special APIs.') +param apiProperties object? + +@description('Optional. Allow only Azure AD authentication. Should be enabled for security reasons.') +param disableLocalAuth bool = true + +import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The customer managed key definition.') +param customerManagedKey customerManagedKeyType? + +@description('Optional. The flag to enable dynamic throttling.') +param dynamicThrottlingEnabled bool = false + +@secure() +@description('Optional. Resource migration token.') +param migrationToken string? + +@description('Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists.') +param restore bool = false + +@description('Optional. Restrict outbound network access.') +param restrictOutboundNetworkAccess bool = true + +@description('Optional. The storage accounts for this resource.') +param userOwnedStorage array? + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityAllType? + @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -module cognitiveServicesPrivateDnsZone '../privateDnsZone.bicep' = if (privateNetworking != null && empty(privateNetworking.?cogServicesPrivateDnsZoneResourceId)) { +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +@description('Optional. Enable/Disable project management feature for AI Foundry.') +param allowProjectManagement bool? + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.cognitiveservices-account.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split(customerManagedKey.?keyVaultResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?keyVaultResourceId!, '/')[2], + split(customerManagedKey.?keyVaultResourceId!, '/')[4] + ) + + resource cMKKey 'keys@2023-07-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName! + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[2], + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[4] + ) +} + +var useExistingService = !empty(existingFoundryProjectResourceId) + +module cognitiveServicesPrivateDnsZone '../privateDnsZone.bicep' = if (!useExistingService && privateNetworking != null && empty(privateNetworking.?cogServicesPrivateDnsZoneResourceId)) { name: take('${name}-cognitiveservices-pdns-deployment', 64) params: { name: 'privatelink.cognitiveservices.${toLower(environment().name) == 'azureusgovernment' ? 'azure.us' : 'azure.com'}' @@ -86,7 +207,7 @@ module cognitiveServicesPrivateDnsZone '../privateDnsZone.bicep' = if (privateNe } } -module openAiPrivateDnsZone '../privateDnsZone.bicep' = if (privateNetworking != null && empty(privateNetworking.?openAIPrivateDnsZoneResourceId)) { +module openAiPrivateDnsZone '../privateDnsZone.bicep' = if (!useExistingService && privateNetworking != null && empty(privateNetworking.?openAIPrivateDnsZoneResourceId)) { name: take('${name}-openai-pdns-deployment', 64) params: { name: 'privatelink.openai.${toLower(environment().name) == 'azureusgovernment' ? 'azure.us' : 'azure.com'}' @@ -95,7 +216,7 @@ module openAiPrivateDnsZone '../privateDnsZone.bicep' = if (privateNetworking != } } -module aiServicesPrivateDnsZone '../privateDnsZone.bicep' = if (privateNetworking != null && empty(privateNetworking.?aiServicesPrivateDnsZoneResourceId)) { +module aiServicesPrivateDnsZone '../privateDnsZone.bicep' = if (!useExistingService && privateNetworking != null && empty(privateNetworking.?aiServicesPrivateDnsZoneResourceId)) { name: take('${name}-ai-services-pdns-deployment', 64) params: { name: 'privatelink.services.ai.${toLower(environment().name) == 'azureusgovernment' ? 'azure.us' : 'azure.com'}' @@ -121,29 +242,68 @@ var aiServicesPrivateDnsZoneResourceId = privateNetworking != null : privateNetworking.?aiServicesPrivateDnsZoneResourceId) : '' -module cognitiveService 'ai-services.bicep' = { - name: take('${name}-aiservices-deployment', 64) - #disable-next-line no-unnecessary-dependson - dependsOn: [cognitiveServicesPrivateDnsZone, openAiPrivateDnsZone, aiServicesPrivateDnsZone] // required due to optional flags that could change dependency +resource cognitiveServiceNew 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' = if(!useExistingService) { + name: name + kind: kind + identity: identity + location: location + tags: tags + sku: { + name: sku + } + properties: { + allowProjectManagement: true // allows project management for Cognitive Services accounts in AI Foundry - FDP updates + customSubDomainName: name + networkAcls: !empty(networkAcls ?? {}) + ? { + defaultAction: networkAcls.?defaultAction + virtualNetworkRules: networkAcls.?virtualNetworkRules ?? [] + ipRules: networkAcls.?ipRules ?? [] + } + : null + publicNetworkAccess: publicNetworkAccess != null + ? publicNetworkAccess + : (!empty(networkAcls) ? 'Enabled' : 'Disabled') + allowedFqdnList: allowedFqdnList + apiProperties: apiProperties + disableLocalAuth: disableLocalAuth + encryption: !empty(customerManagedKey) + ? { + keySource: 'Microsoft.KeyVault' + keyVaultProperties: { + identityClientId: !empty(customerManagedKey.?userAssignedIdentityResourceId ?? '') + ? cMKUserAssignedIdentity.properties.clientId + : null + keyVaultUri: cMKKeyVault.properties.vaultUri + keyName: customerManagedKey!.keyName + keyVersion: !empty(customerManagedKey.?keyVersion ?? '') + ? customerManagedKey!.?keyVersion + : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + } + } + : null + migrationToken: migrationToken + restore: restore + restrictOutboundNetworkAccess: restrictOutboundNetworkAccess + userOwnedStorage: userOwnedStorage + dynamicThrottlingEnabled: dynamicThrottlingEnabled + } +} + +var existingCognitiveServiceDetails = split(existingFoundryProjectResourceId, '/') + +resource cognitiveServiceExisting 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = if(useExistingService) { + name: existingCognitiveServiceDetails[8] + scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) +} +module cognitive_service_dependencies './dependencies.bicep' = if(!useExistingService) { + name: take('${name}-cognitive-service-${cognitiveServiceNew.name}-dependencies', 64) params: { - name: name + projectName: projectName + projectDescription: projectDescription + name: cognitiveServiceNew.name location: location - tags: tags - sku: sku - kind: kind - managedIdentities: { - systemAssigned: true - } deployments: deployments - customSubDomainName: name - disableLocalAuth: false - publicNetworkAccess: privateNetworking != null ? 'Disabled' : 'Enabled' - // rules to allow firewall and virtual network access - networkAcls: { - defaultAction: 'Allow' - virtualNetworkRules: [] - ipRules: [] - } diagnosticSettings: !empty(logAnalyticsWorkspaceResourceId) ? [ { @@ -151,12 +311,12 @@ module cognitiveService 'ai-services.bicep' = { } ] : [] - roleAssignments: roleAssignments - privateEndpoints: privateNetworking != null + lock: lock + privateEndpoints: privateNetworking != null ? [ { - name:'pep-${name}' // private endpoint name - customNetworkInterfaceName: 'nic-${name}' + name:'pep-${name}-aiservices' // private endpoint name + customNetworkInterfaceName: 'nic-${name}-aiservices' subnetResourceId: privateNetworking.?subnetResourceId ?? '' privateDnsZoneGroup: { privateDnsZoneGroupConfigs: [ @@ -174,45 +334,138 @@ module cognitiveService 'ai-services.bicep' = { } ] : [] + roleAssignments: roleAssignments + secretsExportConfiguration: secretsExportConfiguration + sku: sku + tags: tags } } - -module aiProject 'project.bicep' = { - name: take('${name}-ai-project-${projectName}-deployment', 64) +module existing_cognitive_service_dependencies './dependencies.bicep' = if(useExistingService) { + name: take('existing-${name}-cognitive-service-${cognitiveServiceExisting.name}-dependencies', 64) params: { - name: projectName - desc: projectDescription - aiServicesName: cognitiveService.outputs.name + name: cognitiveServiceExisting.name + projectName: projectName + projectDescription: projectDescription + azureExistingAIProjectResourceId: existingFoundryProjectResourceId location: location + deployments: deployments + diagnosticSettings: diagnosticSettings + lock: lock + privateEndpoints: privateEndpoints roleAssignments: roleAssignments + secretsExportConfiguration: secretsExportConfiguration + sku: sku tags: tags - enableTelemetry: enableTelemetry } + scope: resourceGroup(existingCognitiveServiceDetails[2], existingCognitiveServiceDetails[4]) } -@description('The resource group the resources were deployed into.') -output resourceGroupName string = resourceGroup().name - -@description('Name of the Cognitive Services resource.') -output name string = cognitiveService.outputs.name - -@description('Resource ID of the Cognitive Services resource.') -output resourceId string = cognitiveService.outputs.resourceId - -@description('Principal ID of the system assigned managed identity for the Cognitive Services resource. This is only available if the resource has a system assigned managed identity.') -output systemAssignedMIPrincipalId string? = cognitiveService.outputs.?systemAssignedMIPrincipalId - -@description('The endpoint of the Cognitive Services resource.') -output endpoint string = cognitiveService.outputs.endpoint - -import { aiProjectOutputType } from 'project.bicep' -@description('AI Foundry Project information.') -output project aiProjectOutputType = { - name: aiProject.name - resourceId: aiProject.outputs.resourceId - apiEndpoint: aiProject.outputs.apiEndpoint -} +// module cognitiveService 'ai-services.bicep' = { +// name: take('${name}-aiservices-deployment', 64) +// #disable-next-line no-unnecessary-dependson +// dependsOn: [cognitiveServicesPrivateDnsZone, openAiPrivateDnsZone, aiServicesPrivateDnsZone] // required due to optional flags that could change dependency +// params: { +// name: name +// location: location +// tags: tags +// sku: sku +// kind: kind +// managedIdentities: { +// systemAssigned: true +// } +// deployments: deployments +// customSubDomainName: name +// disableLocalAuth: false +// publicNetworkAccess: privateNetworking != null ? 'Disabled' : 'Enabled' +// // rules to allow firewall and virtual network access +// networkAcls: { +// defaultAction: 'Allow' +// virtualNetworkRules: [] +// ipRules: [] +// } +// diagnosticSettings: !empty(logAnalyticsWorkspaceResourceId) +// ? [ +// { +// workspaceResourceId: logAnalyticsWorkspaceResourceId +// } +// ] +// : [] +// roleAssignments: roleAssignments +// privateEndpoints: privateNetworking != null +// ? [ +// { +// name:'pep-${name}' // private endpoint name +// customNetworkInterfaceName: 'nic-${name}' +// subnetResourceId: privateNetworking.?subnetResourceId ?? '' +// privateDnsZoneGroup: { +// privateDnsZoneGroupConfigs: [ +// { +// privateDnsZoneResourceId: cogServicesPrivateDnsZoneResourceId +// } +// { +// privateDnsZoneResourceId: openAIPrivateDnsZoneResourceId +// } +// { +// privateDnsZoneResourceId: aiServicesPrivateDnsZoneResourceId +// } +// ] +// } +// } +// ] +// : [] +// } +// } + + +// module aiProject 'project.bicep' = { +// name: take('${name}-ai-project-${projectName}-deployment', 64) +// params: { +// name: projectName +// desc: projectDescription +// aiServicesName: cognitiveService.outputs.name +// location: location +// roleAssignments: roleAssignments +// tags: tags +// enableTelemetry: enableTelemetry +// } +// } + +var cognitiveService = useExistingService ? cognitiveServiceExisting : cognitiveServiceNew + +@description('The name of the cognitive services account.') +output name string = useExistingService ? cognitiveServiceExisting.name : cognitiveServiceNew.name + +@description('The resource ID of the cognitive services account.') +output resourceId string = useExistingService ? cognitiveServiceExisting.id : cognitiveServiceNew.id + +@description('The resource group the cognitive services account was deployed into.') +output subscriptionId string = useExistingService ? existingCognitiveServiceDetails[2] : subscription().subscriptionId + +@description('The resource group the cognitive services account was deployed into.') +output resourceGroupName string = useExistingService ? existingCognitiveServiceDetails[4] : resourceGroup().name + +@description('The service endpoint of the cognitive services account.') +output endpoint string = useExistingService ? cognitiveServiceExisting.properties.endpoint : cognitiveService.properties.endpoint + +@description('All endpoints available for the cognitive services account, types depends on the cognitive service kind.') +output endpoints endpointType = useExistingService ? cognitiveServiceExisting.properties.endpoints : cognitiveService.properties.endpoints + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = useExistingService ? cognitiveServiceExisting.identity.principalId : cognitiveService.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = useExistingService ? cognitiveServiceExisting.location : cognitiveService.location + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.exportedSecrets : cognitive_service_dependencies.outputs.exportedSecrets + +@description('The private endpoints of the congitive services account.') +output privateEndpoints privateEndpointOutputType[] = useExistingService ? existing_cognitive_service_dependencies.outputs.privateEndpoints : cognitive_service_dependencies.outputs.privateEndpoints + +import { aiProjectOutputType } from './project.bicep' +output aiProjectInfo aiProjectOutputType = useExistingService ? existing_cognitive_service_dependencies.outputs.aiProjectInfo : cognitive_service_dependencies.outputs.aiProjectInfo @export() @description('A custom AVM-aligned type for a role assignment for AI Services and Project.') @@ -229,6 +482,99 @@ type aiServicesRoleAssignmentType = { @description('Optional. The principal type of the assigned principal ID.') principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? } +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for the private endpoint output.') +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The type for a cognitive services account deployment.') +type deploymentType = { + @description('Optional. Specify the name of cognitive service account deployment.') + name: string? + + @description('Required. Properties of Cognitive Services account deployment model.') + model: { + @description('Required. The name of Cognitive Services account deployment model.') + name: string + + @description('Required. The format of Cognitive Services account deployment model.') + format: string + + @description('Required. The version of Cognitive Services account deployment model.') + version: string + } + + @description('Optional. The resource model definition representing SKU.') + sku: { + @description('Required. The name of the resource model definition representing SKU.') + name: string + + @description('Optional. The capacity of the resource model definition representing SKU.') + capacity: int? + + @description('Optional. The tier of the resource model definition representing SKU.') + tier: string? + + @description('Optional. The size of the resource model definition representing SKU.') + size: string? + + @description('Optional. The family of the resource model definition representing SKU.') + family: string? + }? + + @description('Optional. The name of RAI policy.') + raiPolicyName: string? + + @description('Optional. The version upgrade option.') + versionUpgradeOption: string? +} + +@export() +@description('The type for a cognitive services account endpoint.') +type endpointType = { + @description('Type of the endpoint.') + name: string? + @description('The endpoint URI.') + endpoint: string? +} + +@export() +@description('The type of the secrets exported to the provided Key Vault.') +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The name for the accessKey1 secret to create.') + accessKey1Name: string? + + @description('Optional. The name for the accessKey2 secret to create.') + accessKey2Name: string? +} @export() @description('Values to establish private networking for resources that support createing private endpoints.') diff --git a/infra/modules/ai-foundry/project.bicep b/infra/modules/ai-foundry/project.bicep index 17b4475f..0e1a6c6f 100644 --- a/infra/modules/ai-foundry/project.bicep +++ b/infra/modules/ai-foundry/project.bicep @@ -10,52 +10,24 @@ param desc string = name @description('Required. Name of the existing Cognitive Services resource to create the AI Foundry project in.') param aiServicesName string -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' -@description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[] = [] - @description('Optional. Tags to be applied to the resources.') param tags object = {} -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -// using a few built-in roles here that makes sense for Foundry projects only -var builtInRoleNames = { - 'Cognitive Services OpenAI Contributor': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'a001fd3d-188f-4b5d-821b-7da978bf7442' - ) - 'Cognitive Services OpenAI User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' - ) - 'Azure AI Developer': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '64702f94-c441-49e6-a78b-ef80e0188fee' - ) - 'Azure AI User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '53ca6127-db72-4b80-b1b0-d745d6d5456d' - ) -} +@description('Optional. Use this parameter to use an existing AI project resource ID from different resource group') +param azureExistingAIProjectResourceId string = '' -var formattedRoleAssignments = [ - for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { - roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( - roleAssignment.roleDefinitionIdOrName, - '/providers/Microsoft.Authorization/roleDefinitions/' - ) - ? roleAssignment.roleDefinitionIdOrName - : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) - }) -] +// // Extract components from existing AI Project Resource ID if provided +var useExistingProject = !empty(azureExistingAIProjectResourceId) +var existingProjName = useExistingProject ? last(split(azureExistingAIProjectResourceId, '/')) : '' +var existingProjEndpoint = useExistingProject ? format('https://{0}.services.ai.azure.com/api/projects/{1}', aiServicesName, existingProjName) : '' +// Reference to cognitive service in current resource group for new projects resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2024-10-01' existing = { name: aiServicesName } -resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = { +// Create new AI project only if not reusing existing one +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = if(!useExistingProject) { parent: cogServiceReference name: name tags: tags @@ -69,27 +41,12 @@ resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-pre } } -module aiProjectRoleAssignement 'br/public:avm/ptn/authorization/resource-role-assignment:0.1.2' = [ - for (roleAssignment, i) in formattedRoleAssignments: { - name: 'avm.ptn.authorization.resource-role-assignment.${uniqueString(name, roleAssignment.roleDefinitionId, roleAssignment.principalId)}' - params: { - roleDefinitionId: roleAssignment.roleDefinitionId - principalId: roleAssignment.principalId - principalType: 'ServicePrincipal' - resourceId: aiProject.id - enableTelemetry: enableTelemetry - } - } -] - -@description('Name of the AI Foundry project.') -output name string = aiProject.name - -@description('Resource ID of the AI Foundry project.') -output resourceId string = aiProject.id - -@description('API endpoint for the AI Foundry project.') -output apiEndpoint string = aiProject.properties.endpoints['AI Foundry API'] +@description('AI Project metadata including name, resource ID, and API endpoint.') +output aiProjectInfo aiProjectOutputType = { + name: useExistingProject ? existingProjName : aiProject.name + resourceId: useExistingProject ? azureExistingAIProjectResourceId : aiProject.id + apiEndpoint: useExistingProject ? existingProjEndpoint : aiProject.properties.endpoints['AI Foundry API'] +} @export() @description('Output type representing AI project information.') diff --git a/infra/samples/network_subnet_design.md b/infra/samples/network_subnet_design.md index e867e0df..8ea8521e 100644 --- a/infra/samples/network_subnet_design.md +++ b/infra/samples/network_subnet_design.md @@ -36,7 +36,7 @@ This guide explains how to use the sample Bicep program `network-subnet-design.b 3. **Deploy the Sample:** - Use Azure Developer CLI (`azd`) or Azure CLI to deploy the sample and validate your design. 4. **Integrate into Solution:** - - Once validated, use the same approach to build your own `network.bicep` in `infra/modules/` for your solution. Test your solution with i`nfra/main.bicep`. + - Once validated, use the same approach to build your own `network.bicep` in `infra/modules/` for your solution. Test your solution with `infra/main.bicep`. ## Example Directory Structure From 0481bd8b10a4f2945d12f8da9dcf07cda6ddc394 Mon Sep 17 00:00:00 2001 From: Shreyas-Microsoft Date: Wed, 9 Jul 2025 18:31:54 +0530 Subject: [PATCH 2/2] build main bicep --- infra/main.json | 4984 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 4007 insertions(+), 977 deletions(-) diff --git a/infra/main.json b/infra/main.json index 025b31b9..8d5464ea 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "4757767855293314445" + "version": "0.36.177.2456", + "templateHash": "948250848330680679" }, "name": "Modernize Your Code Solution Accelerator", "description": "CSA CTO Gold Standard Solution Accelerator for Modernize Your Code. \r\n" @@ -112,6 +112,13 @@ "description": "Optional. Enable private networking for the resources. Set to true to enable private networking. Defaults to false." } }, + "vmSize": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Size of the Jumpbox Virtual Machine when created. Set to custom value if enablePrivateNetworking is true." + } + }, "vmAdminUsername": { "type": "securestring", "nullable": true, @@ -172,12 +179,248 @@ "description": "Version of the GPT model to deploy:" } }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Use this parameter to use an existing AI project resource ID" + } + }, "existingLogAnalyticsWorkspaceId": { "type": "string", "defaultValue": "" } }, "variables": { + "$fxv#0": { + "ai": { + "aiSearch": "srch-", + "aiServices": "aisa-", + "aiFoundry": "aif-", + "aiFoundryProject": "aifp-", + "aiVideoIndexer": "avi-", + "machineLearningWorkspace": "mlw-", + "openAIService": "oai-", + "botService": "bot-", + "computerVision": "cv-", + "contentModerator": "cm-", + "contentSafety": "cs-", + "customVisionPrediction": "cstv-", + "customVisionTraining": "cstvt-", + "documentIntelligence": "di-", + "faceApi": "face-", + "healthInsights": "hi-", + "immersiveReader": "ir-", + "languageService": "lang-", + "speechService": "spch-", + "translator": "trsl-", + "aiHub": "aih-", + "aiHubProject": "aihp-" + }, + "analytics": { + "analysisServicesServer": "as", + "databricksWorkspace": "dbw-", + "dataExplorerCluster": "dec", + "dataExplorerClusterDatabase": "dedb", + "dataFactory": "adf-", + "digitalTwin": "dt-", + "streamAnalytics": "asa-", + "synapseAnalyticsPrivateLinkHub": "synplh-", + "synapseAnalyticsSQLDedicatedPool": "syndp", + "synapseAnalyticsSparkPool": "synsp", + "synapseAnalyticsWorkspaces": "synw", + "dataLakeStoreAccount": "dls", + "dataLakeAnalyticsAccount": "dla", + "eventHubsNamespace": "evhns-", + "eventHub": "evh-", + "eventGridDomain": "evgd-", + "eventGridSubscriptions": "evgs-", + "eventGridTopic": "evgt-", + "eventGridSystemTopic": "egst-", + "hdInsightHadoopCluster": "hadoop-", + "hdInsightHBaseCluster": "hbase-", + "hdInsightKafkaCluster": "kafka-", + "hdInsightSparkCluster": "spark-", + "hdInsightStormCluster": "storm-", + "hdInsightMLServicesCluster": "mls-", + "iotHub": "iot-", + "provisioningServices": "provs-", + "provisioningServicesCertificate": "pcert-", + "powerBIEmbedded": "pbi-", + "timeSeriesInsightsEnvironment": "tsi-" + }, + "compute": { + "appServiceEnvironment": "ase-", + "appServicePlan": "asp-", + "loadTesting": "lt-", + "availabilitySet": "avail-", + "arcEnabledServer": "arcs-", + "arcEnabledKubernetesCluster": "arck", + "batchAccounts": "ba-", + "cloudService": "cld-", + "communicationServices": "acs-", + "diskEncryptionSet": "des", + "functionApp": "func-", + "gallery": "gal", + "hostingEnvironment": "host-", + "imageTemplate": "it-", + "managedDiskOS": "osdisk", + "managedDiskData": "disk", + "notificationHubs": "ntf-", + "notificationHubsNamespace": "ntfns-", + "proximityPlacementGroup": "ppg-", + "restorePointCollection": "rpc-", + "snapshot": "snap-", + "staticWebApp": "stapp-", + "virtualMachine": "vm", + "virtualMachineScaleSet": "vmss-", + "virtualMachineMaintenanceConfiguration": "mc-", + "virtualMachineStorageAccount": "stvm", + "webApp": "app-" + }, + "containers": { + "aksCluster": "aks-", + "aksSystemNodePool": "npsystem-", + "aksUserNodePool": "np-", + "containerApp": "ca-", + "containerAppsEnvironment": "cae-", + "containerRegistry": "cr", + "containerInstance": "ci", + "serviceFabricCluster": "sf-", + "serviceFabricManagedCluster": "sfmc-" + }, + "databases": { + "cosmosDBDatabase": "cosmos-", + "cosmosDBApacheCassandra": "coscas-", + "cosmosDBMongoDB": "cosmon-", + "cosmosDBNoSQL": "cosno-", + "cosmosDBTable": "costab-", + "cosmosDBGremlin": "cosgrm-", + "cosmosDBPostgreSQL": "cospos-", + "cacheForRedis": "redis-", + "sqlDatabaseServer": "sql-", + "sqlDatabase": "sqldb-", + "sqlElasticJobAgent": "sqlja-", + "sqlElasticPool": "sqlep-", + "mariaDBServer": "maria-", + "mariaDBDatabase": "mariadb-", + "mySQLDatabase": "mysql-", + "postgreSQLDatabase": "psql-", + "sqlServerStretchDatabase": "sqlstrdb-", + "sqlManagedInstance": "sqlmi-" + }, + "developerTools": { + "appConfigurationStore": "appcs-", + "mapsAccount": "map-", + "signalR": "sigr", + "webPubSub": "wps-" + }, + "devOps": { + "managedGrafana": "amg-" + }, + "integration": { + "apiManagementService": "apim-", + "integrationAccount": "ia-", + "logicApp": "logic-", + "serviceBusNamespace": "sbns-", + "serviceBusQueue": "sbq-", + "serviceBusTopic": "sbt-", + "serviceBusTopicSubscription": "sbts-" + }, + "managementGovernance": { + "automationAccount": "aa-", + "applicationInsights": "appi-", + "monitorActionGroup": "ag-", + "monitorDataCollectionRules": "dcr-", + "monitorAlertProcessingRule": "apr-", + "blueprint": "bp-", + "blueprintAssignment": "bpa-", + "dataCollectionEndpoint": "dce-", + "logAnalyticsWorkspace": "log-", + "logAnalyticsQueryPacks": "pack-", + "managementGroup": "mg-", + "purviewInstance": "pview-", + "resourceGroup": "rg-", + "templateSpecsName": "ts-" + }, + "migration": { + "migrateProject": "migr-", + "databaseMigrationService": "dms-", + "recoveryServicesVault": "rsv-" + }, + "networking": { + "applicationGateway": "agw-", + "applicationSecurityGroup": "asg-", + "cdnProfile": "cdnp-", + "cdnEndpoint": "cdne-", + "connections": "con-", + "dnsForwardingRuleset": "dnsfrs-", + "dnsPrivateResolver": "dnspr-", + "dnsPrivateResolverInboundEndpoint": "in-", + "dnsPrivateResolverOutboundEndpoint": "out-", + "firewall": "afw-", + "firewallPolicy": "afwp-", + "expressRouteCircuit": "erc-", + "expressRouteGateway": "ergw-", + "frontDoorProfile": "afd-", + "frontDoorEndpoint": "fde-", + "frontDoorFirewallPolicy": "fdfp-", + "ipGroups": "ipg-", + "loadBalancerInternal": "lbi-", + "loadBalancerExternal": "lbe-", + "loadBalancerRule": "rule-", + "localNetworkGateway": "lgw-", + "natGateway": "ng-", + "networkInterface": "nic-", + "networkSecurityGroup": "nsg-", + "networkSecurityGroupSecurityRules": "nsgsr-", + "networkWatcher": "nw-", + "privateLink": "pl-", + "privateEndpoint": "pep-", + "publicIPAddress": "pip-", + "publicIPAddressPrefix": "ippre-", + "routeFilter": "rf-", + "routeServer": "rtserv-", + "routeTable": "rt-", + "serviceEndpointPolicy": "se-", + "trafficManagerProfile": "traf-", + "userDefinedRoute": "udr-", + "virtualNetwork": "vnet-", + "virtualNetworkGateway": "vgw-", + "virtualNetworkManager": "vnm-", + "virtualNetworkPeering": "peer-", + "virtualNetworkSubnet": "snet-", + "virtualWAN": "vwan-", + "virtualWANHub": "vhub-" + }, + "security": { + "bastion": "bas-", + "keyVault": "kv-", + "keyVaultManagedHSM": "kvmhsm-", + "managedIdentity": "id-", + "sshKey": "sshkey-", + "vpnGateway": "vpng-", + "vpnConnection": "vcn-", + "vpnSite": "vst-", + "webApplicationFirewallPolicy": "waf", + "webApplicationFirewallPolicyRuleGroup": "wafrg" + }, + "storage": { + "storSimple": "ssimp", + "backupVault": "bvault-", + "backupVaultPolicy": "bkpol-", + "fileShare": "share-", + "storageAccount": "st", + "storageSyncService": "sss-" + }, + "virtualDesktop": { + "labServicesPlan": "lp-", + "virtualDesktopHostPool": "vdpool-", + "virtualDesktopApplicationGroup": "vdag-", + "virtualDesktopWorkspace": "vdws-", + "virtualDesktopScalingPlan": "vdscaling-" + } + }, "allTags": "[union(createObject('azd-env-name', parameters('solutionName')), parameters('tags'))]", "resourcesName": "[toLower(trim(replace(replace(replace(replace(replace(replace(format('{0}{1}', parameters('solutionName'), parameters('solutionUniqueToken')), '-', ''), '_', ''), '.', ''), '/', ''), ' ', ''), '*', '')))]", "modelDeployment": { @@ -193,12 +436,13 @@ }, "raiPolicyName": "Microsoft.Default" }, + "abbrs": "[variables('$fxv#0')]", "useExistingLogAnalytics": "[not(empty(parameters('existingLogAnalyticsWorkspaceId')))]", "existingLawSubscription": "[if(variables('useExistingLogAnalytics'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[2], '')]", "existingLawResourceGroup": "[if(variables('useExistingLogAnalytics'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[4], '')]", "existingLawName": "[if(variables('useExistingLogAnalytics'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[8], '')]", "appStorageContainerName": "appstorage", - "containerAppsEnvironmentName": "[format('cae-{0}', variables('resourcesName'))]" + "containerAppsEnvironmentName": "[format('{0}{1}', variables('abbrs').containers.containerAppsEnvironment, variables('resourcesName'))]" }, "resources": { "avmTelemetry": { @@ -241,7 +485,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('id-app-{0}', variables('resourcesName'))]" + "value": "[format('{0}{1}', variables('abbrs').security.managedIdentity, variables('resourcesName'))]" }, "location": { "value": "[parameters('location')]" @@ -724,7 +968,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('log-{0}', variables('resourcesName'))]" + "value": "[format('{0}{1}', variables('abbrs').managementGovernance.logAnalyticsWorkspace, variables('resourcesName'))]" }, "location": { "value": "[parameters('location')]" @@ -3774,16 +4018,16 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('appi-{0}', variables('resourcesName'))]" + "value": "[format('{0}{1}', variables('abbrs').managementGovernance.applicationInsights, variables('resourcesName'))]" }, "location": { "value": "[parameters('location')]" }, - "workspaceResourceId": "[if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').resourceId))]", + "workspaceResourceId": "[if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value))]", "diagnosticSettings": { "value": [ { - "workspaceResourceId": "[if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').resourceId)]" + "workspaceResourceId": "[if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)]" } ] }, @@ -4501,13 +4745,16 @@ "resourcesName": { "value": "[variables('resourcesName')]" }, - "logAnalyticsWorkSpaceResourceId": "[if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').resourceId))]", + "logAnalyticsWorkSpaceResourceId": "[if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value))]", "vmAdminUsername": { "value": "[coalesce(parameters('vmAdminUsername'), 'JumpboxAdminUser')]" }, "vmAdminPassword": { "value": "[coalesce(parameters('vmAdminPassword'), 'JumpboxAdminP@ssw0rd1234!')]" }, + "vmSize": { + "value": "[coalesce(parameters('vmSize'), 'Standard_DS2_v2')]" + }, "location": { "value": "[parameters('location')]" }, @@ -4524,8 +4771,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "3348546999107864209" + "version": "0.36.177.2456", + "templateHash": "7939126224086158159" } }, "parameters": { @@ -4573,6 +4820,12 @@ "metadata": { "description": "Required. Admin password for the VM." } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. VM size for the Jumpbox VM." + } } }, "resources": [ @@ -4611,7 +4864,7 @@ "10.0.0.0/23" ], "networkSecurityGroup": { - "name": "web-nsg", + "name": "nsg-web", "securityRules": [ { "name": "AllowHttpsInbound", @@ -4676,7 +4929,7 @@ }, "bastionConfiguration": { "value": { - "name": "[format('bastion-{0}', parameters('resourcesName'))]", + "name": "[format('bas-{0}', parameters('resourcesName'))]", "subnetAddressPrefixes": [ "10.0.10.0/26" ] @@ -4685,7 +4938,7 @@ "jumpboxConfiguration": { "value": { "name": "[format('vm-jumpbox-{0}', parameters('resourcesName'))]", - "size": "Standard_D2s_v3", + "size": "[parameters('vmSize')]", "username": "[parameters('vmAdminUsername')]", "password": "[parameters('vmAdminPassword')]", "subnet": { @@ -4694,7 +4947,7 @@ "10.0.12.0/23" ], "networkSecurityGroup": { - "name": "jumpbox-nsg", + "name": "nsg-jumbox", "securityRules": [ { "name": "AllowRdpFromBastion", @@ -4729,8 +4982,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "3314975687021704499" + "version": "0.36.177.2456", + "templateHash": "17216090115690766807" } }, "definitions": { @@ -5072,8 +5325,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "1753525663319800389" + "version": "0.36.177.2456", + "templateHash": "6056713917589230954" } }, "definitions": { @@ -5302,7 +5555,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('{0}-{1}', parameters('name'), tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'))]" + "value": "[format('{0}-{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('name'))]" }, "location": { "value": "[parameters('location')]" @@ -7662,7 +7915,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(parameters('bastionConfiguration'), 'name'), format('bastion-{0}', parameters('resourcesName')))]" + "value": "[coalesce(tryGet(parameters('bastionConfiguration'), 'name'), format('bas-{0}', parameters('resourcesName')))]" }, "vnetId": { "value": "[reference('virtualNetwork').outputs.resourceId.value]" @@ -7693,8 +7946,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "361059622889933116" + "version": "0.36.177.2456", + "templateHash": "3102443343421494590" } }, "definitions": { @@ -8232,6 +8485,12 @@ }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" + }, + "publicIPAddressObject": { + "value": { + "name": "[format('pip-{0}', parameters('name'))]", + "zones": [] + } } }, "template": { @@ -9573,8 +9832,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "18079211978491593633" + "version": "0.36.177.2456", + "templateHash": "4959660856295638020" } }, "definitions": { @@ -9826,7 +10085,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('{0}-{1}', parameters('vnetName'), tryGet(parameters('subnet'), 'networkSecurityGroup', 'name'))]" + "value": "[format('{0}-{1}', tryGet(parameters('subnet'), 'networkSecurityGroup', 'name'), parameters('vnetName'))]" }, "location": { "value": "[parameters('location')]" @@ -10911,7 +11170,7 @@ "value": "[parameters('tags')]" }, "zone": { - "value": 2 + "value": 0 }, "imageReference": { "value": { @@ -10926,6 +11185,7 @@ }, "osDisk": { "value": { + "name": "[format('osdisk-{0}', variables('vmName'))]", "managedDisk": { "storageAccountType": "Standard_LRS" } @@ -10937,7 +11197,7 @@ "nicConfigurations": { "value": [ { - "name": "[format('{0}-nic', variables('vmName'))]", + "name": "[format('nic-{0}', variables('vmName'))]", "ipConfigurations": [ { "name": "ipconfig1", @@ -19369,7 +19629,7 @@ "aiServices": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('aiservices-{0}-deployment', variables('resourcesName')), 64)]", + "name": "[take(format('avm.res.cognitive-services.account.{0}', variables('resourcesName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -19377,7 +19637,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('ais-{0}', variables('resourcesName'))]" + "value": "[format('{0}{1}', variables('abbrs').ai.aiFoundry, variables('resourcesName'))]" }, "location": { "value": "[parameters('aiDeploymentsLocation')]" @@ -19394,10 +19654,45 @@ ] }, "projectName": { - "value": "[format('proj-{0}', variables('resourcesName'))]" + "value": "[format('{0}{1}', variables('abbrs').ai.aiFoundryProject, variables('resourcesName'))]" + }, + "projectDescription": { + "value": "[format('{0}{1}', variables('abbrs').ai.aiFoundryProject, variables('resourcesName'))]" }, - "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').resourceId)), createObject('value', ''))]", + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', ''))]", "privateNetworking": "[if(parameters('enablePrivateNetworking'), createObject('value', createObject('virtualNetworkResourceId', reference('network').outputs.vnetResourceId.value, 'subnetResourceId', reference('network').outputs.subnetPrivateEndpointsResourceId.value)), createObject('value', null()))]", + "existingFoundryProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + }, + "disableLocalAuth": { + "value": true + }, + "customSubDomainName": { + "value": "[format('ais-{0}', variables('resourcesName'))]" + }, + "apiProperties": { + "value": {} + }, + "allowProjectManagement": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Allow" + } + }, + "privateEndpoints": { + "value": [] + }, "roleAssignments": { "value": [ { @@ -19431,8 +19726,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "5714740375648051375" + "version": "0.36.177.2456", + "templateHash": "11399294166440815272" }, "name": "AI Services and Project Module", "description": "This module creates an AI Services resource and an AI Foundry project within it. It supports private networking, OpenAI deployments, and role assignments." @@ -19480,6 +19775,221 @@ "description": "A custom AVM-aligned type for a role assignment for AI Services and Project." } }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, "aiServicesPrivateNetworkingType": { "type": "object", "properties": { @@ -19522,6 +20032,144 @@ "description": "Values to establish private networking for resources that support createing private endpoints." } }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, "aiProjectOutputType": { "type": "object", "properties": { @@ -19551,104 +20199,362 @@ } } }, - "deploymentType": { + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." + "description": "Optional. The name of the diagnostic setting." } }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, "nullable": true, "metadata": { - "description": "Optional. The resource model definition representing SKU." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." } }, - "raiPolicyName": { + "logAnalyticsDestinationType": { "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], "nullable": true, "metadata": { - "description": "Optional. The name of RAI policy." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "versionUpgradeOption": { + "workspaceResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The version upgrade option." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "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.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "metadata": { - "description": "The type for a cognitive services account deployment.", + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/cognitive-services/account:0.10.2" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } }, @@ -19726,6 +20632,22 @@ "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } } }, "parameters": { @@ -19813,12 +20735,16 @@ "description": "Optional. The resource ID of the Log Analytics workspace to use for diagnostic settings." } }, + "existingFoundryProjectResourceId": { + "type": "string", + "defaultValue": "" + }, "deployments": { "type": "array", "items": { "$ref": "#/definitions/deploymentType" }, - "defaultValue": [], + "nullable": true, "metadata": { "description": "Optional. Specifies the OpenAI deployments to create." } @@ -19840,6 +20766,58 @@ "description": "Optional. Values to establish private networking for the AI Services resource." } }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, "tags": { "type": "object", "defaultValue": {}, @@ -19847,17 +20825,196 @@ "description": "Optional. Tags to be applied to the resources." } }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "allowProjectManagement": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable project management feature for AI Foundry." + } } }, + "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', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", + "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" + }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-07-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2025-01-31-preview", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "cognitiveServiceNew": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-04-01-preview", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "allowProjectManagement": true, + "customSubDomainName": "[parameters('name')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey", + "cMKUserAssignedIdentity" + ] + }, + "cognitiveServiceExisting": { + "condition": "[variables('useExistingService')]", + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-04-01-preview", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", + "name": "[variables('existingCognitiveServiceDetails')[8]]" + }, "cognitiveServicesPrivateDnsZone": { - "condition": "[and(not(equals(parameters('privateNetworking'), null())), empty(tryGet(parameters('privateNetworking'), 'cogServicesPrivateDnsZoneResourceId')))]", + "condition": "[and(and(not(variables('useExistingService')), not(equals(parameters('privateNetworking'), null()))), empty(tryGet(parameters('privateNetworking'), 'cogServicesPrivateDnsZoneResourceId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[take(format('{0}-cognitiveservices-pdns-deployment', parameters('name')), 64)]", @@ -19884,8 +21041,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "17330037200769804735" + "version": "0.36.177.2456", + "templateHash": "11000727597406726019" } }, "parameters": { @@ -19968,7 +21125,7 @@ } }, "openAiPrivateDnsZone": { - "condition": "[and(not(equals(parameters('privateNetworking'), null())), empty(tryGet(parameters('privateNetworking'), 'openAIPrivateDnsZoneResourceId')))]", + "condition": "[and(and(not(variables('useExistingService')), not(equals(parameters('privateNetworking'), null()))), empty(tryGet(parameters('privateNetworking'), 'openAIPrivateDnsZoneResourceId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[take(format('{0}-openai-pdns-deployment', parameters('name')), 64)]", @@ -19995,8 +21152,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "17330037200769804735" + "version": "0.36.177.2456", + "templateHash": "11000727597406726019" } }, "parameters": { @@ -20079,7 +21236,7 @@ } }, "aiServicesPrivateDnsZone": { - "condition": "[and(not(equals(parameters('privateNetworking'), null())), empty(tryGet(parameters('privateNetworking'), 'aiServicesPrivateDnsZoneResourceId')))]", + "condition": "[and(and(not(variables('useExistingService')), not(equals(parameters('privateNetworking'), null()))), empty(tryGet(parameters('privateNetworking'), 'aiServicesPrivateDnsZoneResourceId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[take(format('{0}-ai-services-pdns-deployment', parameters('name')), 64)]", @@ -20106,8 +21263,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "17330037200769804735" + "version": "0.36.177.2456", + "templateHash": "11000727597406726019" } }, "parameters": { @@ -20123,76 +21280,2254 @@ "description": "Required. The resource ID of the virtual network to link." } }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('name')]", + "location": "global", + "tags": "[parameters('tags')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/'))))]", + "location": "global", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": false, + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" + } + } + } + } + }, + "cognitive_service_dependencies": { + "condition": "[not(variables('useExistingService'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('{0}-cognitive-service-{1}-dependencies', parameters('name'), parameters('name')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "projectName": { + "value": "[parameters('projectName')]" + }, + "projectDescription": { + "value": "[parameters('projectDescription')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "deployments": { + "value": "[parameters('deployments')]" + }, + "diagnosticSettings": "[if(not(empty(parameters('logAnalyticsWorkspaceResourceId'))), createObject('value', createArray(createObject('workspaceResourceId', parameters('logAnalyticsWorkspaceResourceId')))), createObject('value', createArray()))]", + "lock": { + "value": "[parameters('lock')]" + }, + "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('name', format('pep-{0}-aiservices', parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-aiservices', parameters('name')), 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), ''), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'cogServicesPrivateDnsZoneResourceId')), coalesce(reference('cognitiveServicesPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'cogServicesPrivateDnsZoneResourceId')), '')), createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'openAIPrivateDnsZoneResourceId')), coalesce(reference('openAiPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'openAIPrivateDnsZoneResourceId')), '')), createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'aiServicesPrivateDnsZoneResourceId')), coalesce(reference('aiServicesPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'aiServicesPrivateDnsZoneResourceId')), ''))))))), createObject('value', createArray()))]", + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + }, + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.36.177.2456", + "templateHash": "11270933172961789567" + } + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the private endpoint output." + } + }, + "deploymentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + }, + "tier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tier of the resource model definition representing SKU." + } + }, + "size": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The size of the resource model definition representing SKU." + } + }, + "family": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The family of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + }, + "versionUpgradeOption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version upgrade option." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account deployment." + } + }, + "endpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cognitive services account endpoint." + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of the secrets exported to the provided Key Vault." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "projectName": { + "type": "string", + "metadata": { + "description": "Optional: Name for the project which needs to be created." + } + }, + "projectDescription": { + "type": "string", + "metadata": { + "description": "Optional: Description for the project which needs to be created." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "enableReferencedModulesTelemetry": false + }, + "resources": { + "cognitiveService": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2025-04-01-preview", + "name": "[parameters('name')]" + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2025-04-01-preview", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", + "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + } + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[variables('enableReferencedModulesTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12389807800450456797" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13997305779829540948" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-05-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2024-05-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + } + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key2)), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.36.177.2456", + "templateHash": "9150529619101779014" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } } - } - }, - "resources": { - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('name')]", - "location": "global", - "tags": "[parameters('tags')]" }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/'))))]", - "location": "global", - "tags": "[parameters('tags')]", + "aiProject": { + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { - "registrationEnabled": false, - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('projectName')]" + }, + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.36.177.2456", + "templateHash": "18131656256983910282" + } + }, + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Output type representing AI project information." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI Services project." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Required. The location of the Project resource." + } + }, + "desc": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." + } + }, + "aiServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags to be applied to the resources." + } + }, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" + } + } + }, + "variables": { + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" + }, + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2024-10-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-04-01-preview", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" + } + } + }, + "outputs": { + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "metadata": { + "description": "AI Project metadata including name, resource ID, and API endpoint." + }, + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } + } + } } - }, - "dependsOn": [ - "privateDnsZone" - ] + } } }, "outputs": { - "resourceGroupName": { - "type": "string", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "The resource group the private DNS zone was deployed into." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": "[resourceGroup().name]" + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", "metadata": { - "description": "The resource ID of the private DNS zone." + "description": "The private endpoints of the congitive services account." }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } } } - } + }, + "dependsOn": [ + "aiServicesPrivateDnsZone", + "cognitiveServiceNew", + "cognitiveServicesPrivateDnsZone", + "openAiPrivateDnsZone" + ] }, - "cognitiveService": { + "existing_cognitive_service_dependencies": { + "condition": "[variables('useExistingService')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('{0}-aiservices-deployment', parameters('name')), 64)]", + "name": "[take(format('existing-{0}-cognitive-service-{1}-dependencies', parameters('name'), variables('existingCognitiveServiceDetails')[8]), 64)]", + "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", + "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -20200,47 +23535,44 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('name')]" + "value": "[variables('existingCognitiveServiceDetails')[8]]" }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" + "projectName": { + "value": "[parameters('projectName')]" }, - "sku": { - "value": "[parameters('sku')]" + "projectDescription": { + "value": "[parameters('projectDescription')]" }, - "kind": { - "value": "[parameters('kind')]" + "azureExistingAIProjectResourceId": { + "value": "[parameters('existingFoundryProjectResourceId')]" }, - "managedIdentities": { - "value": { - "systemAssigned": true - } + "location": { + "value": "[parameters('location')]" }, "deployments": { "value": "[parameters('deployments')]" }, - "customSubDomainName": { - "value": "[parameters('name')]" + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "disableLocalAuth": { - "value": false + "lock": { + "value": "[parameters('lock')]" }, - "publicNetworkAccess": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "networkAcls": { - "value": { - "defaultAction": "Allow", - "virtualNetworkRules": [], - "ipRules": [] - } + "privateEndpoints": { + "value": "[parameters('privateEndpoints')]" }, - "diagnosticSettings": "[if(not(empty(parameters('logAnalyticsWorkspaceResourceId'))), createObject('value', createArray(createObject('workspaceResourceId', parameters('logAnalyticsWorkspaceResourceId')))), createObject('value', createArray()))]", "roleAssignments": { "value": "[parameters('roleAssignments')]" }, - "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('name', format('pep-{0}-aiservices', parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-aiservices', parameters('name')), 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), ''), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'cogServicesPrivateDnsZoneResourceId')), coalesce(reference('cognitiveServicesPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'cogServicesPrivateDnsZoneResourceId')), '')), createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'openAIPrivateDnsZoneResourceId')), coalesce(reference('openAiPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'openAIPrivateDnsZoneResourceId')), '')), createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'aiServicesPrivateDnsZoneResourceId')), coalesce(reference('aiServicesPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'aiServicesPrivateDnsZoneResourceId')), ''))))))), createObject('value', createArray()))]" + "secretsExportConfiguration": { + "value": "[parameters('secretsExportConfiguration')]" + }, + "sku": { + "value": "[parameters('sku')]" + }, + "tags": { + "value": "[parameters('tags')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -20249,11 +23581,9 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "13817916222456032922" - }, - "name": "Cognitive Services", - "description": "This module deploys a Cognitive Service." + "version": "0.36.177.2456", + "templateHash": "11270933172961789567" + } }, "definitions": { "privateEndpointOutputType": { @@ -20471,36 +23801,6 @@ "description": "The type of the secrets exported to the provided Key Vault." } }, - "_1.lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, "_1.privateEndpointCustomDnsConfigType": { "type": "object", "properties": { @@ -20610,6 +23910,64 @@ } } }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, + "metadata": { + "description": "Output type representing AI project information.", + "__bicep_imported_from!": { + "sourceTemplate": "project.bicep" + } + } + }, "diagnosticSettingFullType": { "type": "object", "properties": { @@ -20732,29 +24090,31 @@ } } }, - "managedIdentityAllType": { + "lockType": { "type": "object", "properties": { - "systemAssigned": { - "type": "bool", + "name": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." + "description": "Optional. Specify the name of lock." } }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + "description": "Optional. Specify the type of lock." } } }, "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.", + "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" } @@ -20864,7 +24224,7 @@ } }, "lock": { - "$ref": "#/definitions/_1.lockType", + "$ref": "#/definitions/lockType", "nullable": true, "metadata": { "description": "Optional. Specify the type of lock." @@ -20976,6 +24336,22 @@ "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" } } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } } }, "parameters": { @@ -20985,39 +24361,6 @@ "description": "Required. The name of Cognitive Services account." } }, - "kind": { - "type": "string", - "defaultValue": "AIServices", - "allowedValues": [ - "AIServices", - "AnomalyDetector", - "CognitiveServices", - "ComputerVision", - "ContentModerator", - "ContentSafety", - "ConversationalLanguageUnderstanding", - "CustomVision.Prediction", - "CustomVision.Training", - "Face", - "FormRecognizer", - "HealthInsights", - "ImmersiveReader", - "Internal.AllInOne", - "LUIS", - "LUIS.Authoring", - "LanguageAuthoring", - "MetricsAdvisor", - "OpenAI", - "Personalizer", - "QnAMaker.v2", - "SpeechServices", - "TextAnalytics", - "TextTranslation" - ], - "metadata": { - "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, "sku": { "type": "string", "defaultValue": "S0", @@ -21051,46 +24394,28 @@ "description": "Optional. Location for all Resources." } }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "customSubDomainName": { - "type": "string", + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + "description": "Optional. Tags of the resource." } }, - "networkAcls": { - "type": "object", + "deployments": { + "type": "array", + "items": { + "$ref": "#/definitions/deploymentType" + }, "nullable": true, "metadata": { - "description": "Optional. A collection of rules governing the accessibility from specific network locations." + "description": "Optional. Array of deployments about cognitive service accounts to create." } }, - "networkInjectionSubnetResourceId": { - "type": "string", + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", "nullable": true, "metadata": { - "description": "Optional. The network injection subnet resource Id for the Cognitive Services account. This allows to use the AI Services account with a virtual network." + "description": "Optional. Key vault reference and secret settings for the module's secrets export." } }, "privateEndpoints": { @@ -21103,6 +24428,13 @@ "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, "roleAssignments": { "type": "array", "items": { @@ -21113,84 +24445,33 @@ "description": "Optional. Array of role assignments to create." } }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "allowedFqdnList": { + "diagnosticSettings": { "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, "nullable": true, "metadata": { - "description": "Optional. List of allowed FQDN." - } - }, - "apiProperties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The API properties for special APIs." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." - } - }, - "dynamicThrottlingEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag to enable dynamic throttling." - } - }, - "migrationToken": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. Resource migration token." - } - }, - "restore": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." - } - }, - "restrictOutboundNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Restrict outbound network access." + "description": "Optional. The diagnostic settings of the service." } }, - "userOwnedStorage": { - "type": "array", - "nullable": true, + "projectName": { + "type": "string", "metadata": { - "description": "Optional. The storage accounts for this resource." + "description": "Optional: Name for the project which needs to be created." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, + "projectDescription": { + "type": "string", "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Optional: Description for the project which needs to be created." } }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, + "azureExistingAIProjectResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." + "description": "Optional: Provide the existing project resource id in case if it needs to be reused" } } }, @@ -21202,9 +24483,6 @@ "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", @@ -21230,41 +24508,21 @@ "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "enableReferencedModulesTelemetry": false }, "resources": { "cognitiveService": { + "existing": true, "type": "Microsoft.CognitiveServices/accounts", "apiVersion": "2025-04-01-preview", - "name": "[parameters('name')]", - "kind": "[parameters('kind')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "properties": { - "customSubDomainName": "[parameters('customSubDomainName')]", - "allowProjectManagement": true, - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", - "allowedFqdnList": "[parameters('allowedFqdnList')]", - "apiProperties": "[parameters('apiProperties')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "networkInjections": "[if(not(equals(parameters('networkInjectionSubnetResourceId'), null())), createArray(createObject('scenario', 'agent', 'subnetArmId', parameters('networkInjectionSubnetResourceId'), 'useMicrosoftManagedNetwork', false())), null())]", - "encryption": null, - "migrationToken": "[parameters('migrationToken')]", - "restore": "[parameters('restore')]", - "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", - "userOwnedStorage": "[parameters('userOwnedStorage')]", - "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" - } + "name": "[parameters('name')]" }, "cognitiveService_deployments": { "copy": { @@ -21274,17 +24532,25 @@ "batchSize": 1 }, "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2024-10-01", + "apiVersion": "2025-04-01-preview", "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", "properties": { "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]", - "dependsOn": [ - "cognitiveService" - ] + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" + }, + "cognitiveService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } }, "cognitiveService_diagnosticSettings": { "copy": { @@ -21322,10 +24588,7 @@ "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "cognitiveService" - ] + } }, "cognitiveService_roleAssignments": { "copy": { @@ -21344,10 +24607,7 @@ "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "cognitiveService" - ] + } }, "cognitiveService_privateEndpoints": { "copy": { @@ -21356,7 +24616,7 @@ }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[take(format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex()), 64)]", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", "properties": { @@ -21379,6 +24639,9 @@ "location": { "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, "privateDnsZoneGroup": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, @@ -22098,657 +25361,423 @@ } } } - }, - "dependsOn": [ - "cognitiveService" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cognitive services account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cognitive services account." - }, - "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The service endpoint of the cognitive services account." - }, - "value": "[reference('cognitiveService').endpoint]" - }, - "endpoints": { - "$ref": "#/definitions/endpointType", - "metadata": { - "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." - }, - "value": "[reference('cognitiveService').endpoints]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('cognitiveService', '2025-04-01-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('cognitiveService', '2025-04-01-preview', 'full').location]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "aiServicesPrivateDnsZone", - "cognitiveServicesPrivateDnsZone", - "openAiPrivateDnsZone" - ] - }, - "aiProject": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[reference('cognitiveService').outputs.name.value]" - }, - "location": { - "value": "[parameters('location')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "13536480337268273627" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." } }, - "roleAssignmentType": { - "type": "object", + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", "properties": { - "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\"." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key2)), createArray()))]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "_generator": { + "name": "bicep", + "version": "0.36.177.2456", + "templateHash": "9150529619101779014" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } } } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services project." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. The location of the Project resource." - } - }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } - }, - "aiServicesName": { - "type": "string", - "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" } - ], - "builtInRoleNames": { - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Azure AI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d')]" - } - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2024-10-01", - "name": "[parameters('aiServicesName')]" }, "aiProject": { - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-04-01-preview", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" - } - }, - "aiProjectRoleAssignement": { - "copy": { - "name": "aiProjectRoleAssignement", - "count": "[length(variables('formattedRoleAssignments'))]" - }, + "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('avm.ptn.authorization.resource-role-assignment.{0}', uniqueString(parameters('name'), variables('formattedRoleAssignments')[copyIndex()].roleDefinitionId, variables('formattedRoleAssignments')[copyIndex()].principalId))]", + "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "roleDefinitionId": { - "value": "[variables('formattedRoleAssignments')[copyIndex()].roleDefinitionId]" + "name": { + "value": "[parameters('projectName')]" }, - "principalId": { - "value": "[variables('formattedRoleAssignments')[copyIndex()].principalId]" + "desc": { + "value": "[parameters('projectDescription')]" + }, + "aiServicesName": { + "value": "[parameters('name')]" }, - "principalType": { - "value": "ServicePrincipal" + "location": { + "value": "[parameters('location')]" }, - "resourceId": { - "value": "[resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name'))]" + "tags": { + "value": "[parameters('tags')]" }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" + "azureExistingAIProjectResourceId": { + "value": "[parameters('azureExistingAIProjectResourceId')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.32.4.45862", - "templateHash": "14634305923902101494" - }, - "name": "Resource-scoped role assignment", - "description": "This module deploys a Role Assignment for a specific resource." + "version": "0.36.177.2456", + "templateHash": "18131656256983910282" + } }, - "parameters": { - "resourceId": { - "type": "string", + "definitions": { + "aiProjectOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the AI project." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the AI project." + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Required. API endpoint for the AI project." + } + } + }, "metadata": { - "description": "Required. The scope for the role assignment, fully qualified resourceId." + "__bicep_export!": true, + "description": "Output type representing AI project information." } - }, + } + }, + "parameters": { "name": { "type": "string", - "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", "metadata": { - "description": "Optional. The unique guid name for the role assignment." + "description": "Required. Name of the AI Services project." } }, - "roleDefinitionId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The role definition ID for the role assignment." + "description": "Required. The location of the Project resource." } }, - "roleName": { + "desc": { "type": "string", - "defaultValue": "", + "defaultValue": "[parameters('name')]", "metadata": { - "description": "Optional. The name for the role, used for logging." + "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." } }, - "principalId": { + "aiServicesName": { "type": "string", "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." } }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Tags to be applied to the resources." } }, - "description": { + "azureExistingAIProjectResourceId": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. The description of role assignment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" } } }, "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string" - }, - "name": { - "type": "string" - }, - "roleDefinitionId": { - "type": "string" - }, - "principalId": { - "type": "string" - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string" - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "principalType": "[[parameters('principalType')]", - "description": "[[parameters('description')]" - } - } - ], - "outputs": { - "roleAssignmentId": { - "type": "string", - "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" - } - } - } + "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", + "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", + "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.2', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "resources": { + "cogServiceReference": { + "existing": true, + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2024-10-01", + "name": "[parameters('aiServicesName')]" + }, + "aiProject": { + "condition": "[not(variables('useExistingProject'))]", + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-04-01-preview", + "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "Outer" - }, - "template": "[variables('$fxv#0')]", - "parameters": { - "scope": { - "value": "[parameters('resourceId')]" - }, - "name": { - "value": "[parameters('name')]" - }, - "roleDefinitionId": { - "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" - }, - "principalId": { - "value": "[parameters('principalId')]" - }, - "principalType": { - "value": "[parameters('principalType')]" - }, - "description": { - "value": "[parameters('description')]" - } - } + "description": "[parameters('desc')]", + "displayName": "[parameters('name')]" } } - ], + }, "outputs": { - "name": { - "type": "string", + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", "metadata": { - "description": "The GUID of the Role Assignment." + "description": "AI Project metadata including name, resource ID, and API endpoint." }, - "value": "[parameters('name')]" - }, - "roleName": { - "type": "string", - "metadata": { - "description": "The name for the role, used for logging." - }, - "value": "[parameters('roleName')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" + "value": { + "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", + "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", + "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" + } } } } - }, - "dependsOn": [ - "aiProject" - ] + } } }, "outputs": { - "name": { - "type": "string", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "Name of the AI Foundry project." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": "[parameters('name')]" + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of the AI Foundry project." + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" }, - "value": "[resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name'))]" - }, - "apiEndpoint": { - "type": "string", "metadata": { - "description": "API endpoint for the AI Foundry project." + "description": "The private endpoints of the congitive services account." }, - "value": "[reference('aiProject').endpoints['AI Foundry API']]" + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[reference('aiProject').outputs.aiProjectInfo.value]" } } } - }, - "dependsOn": [ - "cognitiveService" - ] + } } }, "outputs": { - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the resources were deployed into." + "description": "The name of the cognitive services account." }, - "value": "[resourceGroup().name]" + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "Name of the Cognitive Services resource." + "description": "The resource ID of the cognitive services account." }, - "value": "[reference('cognitiveService').outputs.name.value]" + "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" }, - "resourceId": { + "subscriptionId": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" + }, + "endpoint": { "type": "string", "metadata": { - "description": "Resource ID of the Cognitive Services resource." + "description": "The service endpoint of the cognitive services account." + }, + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')).properties.endpoint)]" + }, + "endpoints": { + "$ref": "#/definitions/endpointType", + "metadata": { + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." }, - "value": "[reference('cognitiveService').outputs.resourceId.value]" + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')).properties.endpoints)]" }, "systemAssignedMIPrincipalId": { "type": "string", "nullable": true, "metadata": { - "description": "Principal ID of the system assigned managed identity for the Cognitive Services resource. This is only available if the resource has a system assigned managed identity." + "description": "The principal ID of the system assigned identity." }, - "value": "[tryGet(tryGet(reference('cognitiveService').outputs, 'systemAssignedMIPrincipalId'), 'value')]" + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')), 'identity'), 'principalId'))]" }, - "endpoint": { + "location": { "type": "string", "metadata": { - "description": "The endpoint of the Cognitive Services resource." + "description": "The location the resource was deployed into." }, - "value": "[reference('cognitiveService').outputs.endpoint.value]" + "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')).location)]" }, - "project": { - "$ref": "#/definitions/aiProjectOutputType", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "AI Foundry Project information." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "value": { - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", - "resourceId": "[reference('aiProject').outputs.resourceId.value]", - "apiEndpoint": "[reference('aiProject').outputs.apiEndpoint.value]" - } + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.exportedSecrets.value, reference('cognitive_service_dependencies').outputs.exportedSecrets.value)]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.privateEndpoints.value, reference('cognitive_service_dependencies').outputs.privateEndpoints.value)]" + }, + "aiProjectInfo": { + "$ref": "#/definitions/aiProjectOutputType", + "value": "[if(variables('useExistingService'), reference('existing_cognitive_service_dependencies').outputs.aiProjectInfo.value, reference('cognitive_service_dependencies').outputs.aiProjectInfo.value)]" } } } @@ -22770,7 +25799,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[take(format('st{0}', variables('resourcesName')), 24)]" + "value": "[take(format('{0}{1}', variables('abbrs').storage.storageAccount, variables('resourcesName')), 24)]" }, "location": { "value": "[parameters('location')]" @@ -22779,7 +25808,7 @@ "value": "[variables('allTags')]" }, "skuName": "[if(parameters('enableRedundancy'), createObject('value', 'Standard_GZRS'), createObject('value', 'Standard_LRS'))]", - "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').resourceId)), createObject('value', ''))]", + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', ''))]", "privateNetworking": "[if(parameters('enablePrivateNetworking'), createObject('value', createObject('virtualNetworkResourceId', reference('network').outputs.vnetResourceId.value, 'subnetResourceId', reference('network').outputs.subnetPrivateEndpointsResourceId.value)), createObject('value', null()))]", "containers": { "value": [ @@ -22811,8 +25840,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "14741977092620349839" + "version": "0.36.177.2456", + "templateHash": "6558993818536161993" } }, "definitions": { @@ -23032,8 +26061,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "17330037200769804735" + "version": "0.36.177.2456", + "templateHash": "11000727597406726019" } }, "parameters": { @@ -23143,8 +26172,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "17330037200769804735" + "version": "0.36.177.2456", + "templateHash": "11000727597406726019" } }, "parameters": { @@ -23292,7 +26321,7 @@ "value": true }, "diagnosticSettings": "[if(not(empty(parameters('logAnalyticsWorkspaceResourceId'))), createObject('value', createArray(createObject('workspaceResourceId', parameters('logAnalyticsWorkspaceResourceId')))), createObject('value', createArray()))]", - "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'blobPrivateDnsZoneResourceId')), coalesce(reference('blobPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'blobPrivateDnsZoneResourceId')), '')))), 'service', 'blob', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')), createObject('privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'filePrivateDnsZoneResourceId')), coalesce(reference('filePrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'filePrivateDnsZoneResourceId')), '')))), 'service', 'file', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')))), createObject('value', createArray()))]", + "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('name', format('pep-blob-{0}', parameters('name')), 'customNetworkInterfaceName', format('nic-blob-{0}', parameters('name')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'blobPrivateDnsZoneResourceId')), coalesce(reference('blobPrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'blobPrivateDnsZoneResourceId')), '')))), 'service', 'blob', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')), createObject('name', format('pep-file-{0}', parameters('name')), 'customNetworkInterfaceName', format('nic-file-{0}', parameters('name')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'filePrivateDnsZoneResourceId')), coalesce(reference('filePrivateDnsZone').outputs.resourceId.value, ''), tryGet(parameters('privateNetworking'), 'filePrivateDnsZoneResourceId')), '')))), 'service', 'file', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')))), createObject('value', createArray()))]", "roleAssignments": { "value": "[parameters('roleAssignments')]" }, @@ -29008,14 +32037,14 @@ "metadata": { "description": "Name of the Storage Account." }, - "value": "[listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('{0}-sa-deployment', parameters('name')), 64)), '2022-09-01').name]" + "value": "[reference('storageAccount').outputs.name.value]" }, "resourceId": { "type": "string", "metadata": { "description": "Resource ID of the Storage Account." }, - "value": "[listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('{0}-sa-deployment', parameters('name')), 64)), '2022-09-01').resourceId]" + "value": "[reference('storageAccount').outputs.resourceId.value]" } } } @@ -29037,7 +32066,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[take(format('kv-{0}', variables('resourcesName')), 24)]" + "value": "[take(format('{0}{1}', variables('abbrs').security.keyVault, variables('resourcesName')), 24)]" }, "location": { "value": "[parameters('location')]" @@ -29045,14 +32074,14 @@ "sku": { "value": "standard" }, - "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').resourceId)), createObject('value', ''))]", + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', ''))]", "privateNetworking": "[if(parameters('enablePrivateNetworking'), createObject('value', createObject('virtualNetworkResourceId', reference('network').outputs.vnetResourceId.value, 'subnetResourceId', reference('network').outputs.subnetPrivateEndpointsResourceId.value)), createObject('value', null()))]", "roleAssignments": { "value": [ { - "principalId": "[coalesce(tryGet(tryGet(reference('aiServices').outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]", + "principalId": "[coalesce(tryGet(tryGet(reference('aiServices').outputs, 'systemAssignedMIPrincipalId'), 'value'), reference('appIdentity').outputs.principalId.value)]", "principalType": "ServicePrincipal", - "roleDefinitionIdOrName": "Key Vault Reader" + "roleDefinitionIdOrName": "Key Vault Administrator" } ] }, @@ -29070,8 +32099,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "11020159786085563276" + "version": "0.36.177.2456", + "templateHash": "5637162512351801321" } }, "definitions": { @@ -29435,8 +32464,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "17330037200769804735" + "version": "0.36.177.2456", + "templateHash": "11000727597406726019" } }, "parameters": { @@ -29571,7 +32600,7 @@ "value": 7 }, "diagnosticSettings": "[if(not(empty(parameters('logAnalyticsWorkspaceResourceId'))), createObject('value', createArray(createObject('workspaceResourceId', parameters('logAnalyticsWorkspaceResourceId')))), createObject('value', createArray()))]", - "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId')), coalesce(reference('privateDnsZone').outputs.resourceId.value, ''), coalesce(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId'), '')), '')))), 'service', 'vault', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')))), createObject('value', createArray()))]", + "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('name', format('pep-{0}', parameters('name')), 'customNetworkInterfaceName', format('nic-{0}', parameters('name')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId')), coalesce(reference('privateDnsZone').outputs.resourceId.value, ''), coalesce(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId'), '')), '')))), 'service', 'vault', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')))), createObject('value', createArray()))]", "roleAssignments": { "value": "[parameters('roleAssignments')]" }, @@ -32724,6 +35753,7 @@ }, "dependsOn": [ "aiServices", + "appIdentity", "logAnalyticsWorkspace", "network" ] @@ -32739,7 +35769,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[take(format('cosmos-{0}', variables('resourcesName')), 44)]" + "value": "[take(format('{0}{1}', variables('abbrs').databases.cosmosDBDatabase, variables('resourcesName')), 44)]" }, "location": { "value": "[parameters('location')]" @@ -32747,7 +35777,7 @@ "dataAccessIdentityPrincipalId": { "value": "[reference('appIdentity').outputs.principalId.value]" }, - "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').resourceId)), createObject('value', ''))]", + "logAnalyticsWorkspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', ''))]", "zoneRedundant": { "value": "[parameters('enableRedundancy')]" }, @@ -32767,8 +35797,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "7579999244356278483" + "version": "0.36.177.2456", + "templateHash": "9062224490726814247" } }, "definitions": { @@ -32990,8 +36020,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "17330037200769804735" + "version": "0.36.177.2456", + "templateHash": "11000727597406726019" } }, "parameters": { @@ -33125,7 +36155,7 @@ "value": "[not(equals(parameters('privateNetworking'), null()))]" }, "diagnosticSettings": "[if(not(empty(parameters('logAnalyticsWorkspaceResourceId'))), createObject('value', createArray(createObject('workspaceResourceId', parameters('logAnalyticsWorkspaceResourceId')))), createObject('value', createArray()))]", - "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId')), coalesce(reference('privateDnsZone').outputs.resourceId.value, ''), coalesce(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId'), '')), '')))), 'service', 'Sql', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')))), createObject('value', createArray()))]", + "privateEndpoints": "[if(not(equals(parameters('privateNetworking'), null())), createObject('value', createArray(createObject('name', format('pep-{0}', parameters('name')), 'customNetworkInterfaceName', format('nic-{0}', parameters('name')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', if(not(equals(parameters('privateNetworking'), null())), if(empty(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId')), coalesce(reference('privateDnsZone').outputs.resourceId.value, ''), coalesce(tryGet(parameters('privateNetworking'), 'privateDnsZoneResourceId'), '')), '')))), 'service', 'Sql', 'subnetResourceId', coalesce(tryGet(parameters('privateNetworking'), 'subnetResourceId'), '')))), createObject('value', createArray()))]", "sqlDatabases": { "value": [ { @@ -36955,21 +39985,21 @@ "metadata": { "description": "Name of the Cosmos DB Account resource." }, - "value": "[listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('{0}-account-deployment', parameters('name')), 64)), '2022-09-01').name]" + "value": "[reference('cosmosAccount').outputs.name.value]" }, "resourceId": { "type": "string", "metadata": { "description": "Resource ID of the Cosmos DB Account." }, - "value": "[listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('{0}-account-deployment', parameters('name')), 64)), '2022-09-01').resourceId]" + "value": "[reference('cosmosAccount').outputs.resourceId.value]" }, "endpoint": { "type": "string", "metadata": { "description": "Endpoint of the Cosmos DB Account." }, - "value": "[listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('{0}-account-deployment', parameters('name')), 64)), '2022-09-01').endpoint]" + "value": "[reference('cosmosAccount').outputs.endpoint.value]" }, "databaseName": { "type": "string", @@ -37032,7 +40062,7 @@ } }, "appInsightsConnectionString": "[if(parameters('enableMonitoring'), createObject('value', reference('applicationInsights').outputs.connectionString.value), createObject('value', null()))]", - "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsConfiguration', createObject('customerId', if(variables('useExistingLogAnalytics'), reference('existingLogAnalyticsWorkspace').customerId, listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').logAnalyticsWorkspaceId), 'sharedKey', if(variables('useExistingLogAnalytics'), listKeys('existingLogAnalyticsWorkspace', '2020-08-01').primarySharedKey, listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('log-analytics-{0}-deployment', variables('resourcesName')), 64)), '2022-09-01').primarySharedKey)))), createObject('value', createObject()))]", + "appLogsConfiguration": "[if(parameters('enableMonitoring'), createObject('value', createObject('destination', 'log-analytics', 'logAnalyticsConfiguration', createObject('customerId', if(variables('useExistingLogAnalytics'), reference('existingLogAnalyticsWorkspace').customerId, reference('logAnalyticsWorkspace').outputs.logAnalyticsWorkspaceId.value), 'sharedKey', if(variables('useExistingLogAnalytics'), listKeys('existingLogAnalyticsWorkspace', '2020-08-01').primarySharedKey, listOutputsWithSecureValues('logAnalyticsWorkspace', '2022-09-01').primarySharedKey)))), createObject('value', createObject()))]", "workloadProfiles": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', 'Consumption', 'workloadProfileType', 'Consumption'))), createObject('value', createArray()))]", "tags": { "value": "[variables('allTags')]" @@ -37930,7 +40960,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[take(format('ca-{0}backend', variables('resourcesName')), 32)]" + "value": "[take(format('{0}backend-{1}', variables('abbrs').containers.containerApp, variables('resourcesName')), 32)]" }, "location": { "value": "[parameters('location')]" @@ -37950,7 +40980,7 @@ { "name": "cmsabackend", "image": "[format('cmsacontainerreg.azurecr.io/cmsabackend:{0}', parameters('imageVersion'))]", - "env": "[concat(createArray(createObject('name', 'COSMOSDB_ENDPOINT', 'value', reference('cosmosDb').outputs.endpoint.value), createObject('name', 'COSMOSDB_DATABASE', 'value', reference('cosmosDb').outputs.databaseName.value), createObject('name', 'COSMOSDB_BATCH_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.batch), createObject('name', 'COSMOSDB_FILE_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.file), createObject('name', 'COSMOSDB_LOG_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.log), createObject('name', 'AZURE_BLOB_ACCOUNT_NAME', 'value', reference('storageAccount').outputs.name.value), createObject('name', 'AZURE_BLOB_CONTAINER_NAME', 'value', variables('appStorageContainerName')), createObject('name', 'AZURE_OPENAI_ENDPOINT', 'value', format('https://{0}.openai.azure.com/', reference('aiServices').outputs.name.value)), createObject('name', 'MIGRATOR_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'PICKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'FIXER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SEMANTIC_VERIFIER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SYNTAX_CHECKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SELECTION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'TERMINATION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME', 'value', variables('modelDeployment').name), createObject('name', 'AI_PROJECT_ENDPOINT', 'value', reference('aiServices').outputs.project.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING', 'value', reference('aiServices').outputs.project.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_NAME', 'value', reference('aiServices').outputs.project.value.name), createObject('name', 'AZURE_AI_AGENT_RESOURCE_GROUP_NAME', 'value', resourceGroup().name), createObject('name', 'AZURE_AI_AGENT_SUBSCRIPTION_ID', 'value', subscription().subscriptionId), createObject('name', 'AZURE_AI_AGENT_ENDPOINT', 'value', reference('aiServices').outputs.project.value.apiEndpoint), createObject('name', 'AZURE_CLIENT_ID', 'value', reference('appIdentity').outputs.clientId.value)), if(parameters('enableMonitoring'), createArray(createObject('name', 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY', 'value', reference('applicationInsights').outputs.instrumentationKey.value), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', reference('applicationInsights').outputs.connectionString.value)), createArray()))]", + "env": "[concat(createArray(createObject('name', 'COSMOSDB_ENDPOINT', 'value', reference('cosmosDb').outputs.endpoint.value), createObject('name', 'COSMOSDB_DATABASE', 'value', reference('cosmosDb').outputs.databaseName.value), createObject('name', 'COSMOSDB_BATCH_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.batch), createObject('name', 'COSMOSDB_FILE_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.file), createObject('name', 'COSMOSDB_LOG_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.log), createObject('name', 'AZURE_BLOB_ACCOUNT_NAME', 'value', reference('storageAccount').outputs.name.value), createObject('name', 'AZURE_BLOB_CONTAINER_NAME', 'value', variables('appStorageContainerName')), createObject('name', 'AZURE_OPENAI_ENDPOINT', 'value', format('https://{0}.openai.azure.com/', reference('aiServices').outputs.name.value)), createObject('name', 'MIGRATOR_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'PICKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'FIXER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SEMANTIC_VERIFIER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SYNTAX_CHECKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SELECTION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'TERMINATION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME', 'value', variables('modelDeployment').name), createObject('name', 'AI_PROJECT_ENDPOINT', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_NAME', 'value', reference('aiServices').outputs.aiProjectInfo.value.name), createObject('name', 'AZURE_AI_AGENT_RESOURCE_GROUP_NAME', 'value', resourceGroup().name), createObject('name', 'AZURE_AI_AGENT_SUBSCRIPTION_ID', 'value', subscription().subscriptionId), createObject('name', 'AZURE_AI_AGENT_ENDPOINT', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_CLIENT_ID', 'value', reference('appIdentity').outputs.clientId.value)), if(parameters('enableMonitoring'), createArray(createObject('name', 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY', 'value', reference('applicationInsights').outputs.instrumentationKey.value), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', reference('applicationInsights').outputs.connectionString.value)), createArray()))]", "resources": { "cpu": 1, "memory": "2.0Gi" @@ -39430,7 +42460,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[take(format('ca-{0}frontend', variables('resourcesName')), 32)]" + "value": "[take(format('{0}frontend-{1}', variables('abbrs').containers.containerApp, variables('resourcesName')), 32)]" }, "location": { "value": "[parameters('location')]"