Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 29 additions & 11 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ param gptModelVersion string = '2024-08-06'

param existingLogAnalyticsWorkspaceId string = ''

@description('Use this parameter to use an existing AI project resource ID')
param azureExistingAIProjectResourceId string = ''

var allTags = union(
{
'azd-env-name': solutionName
Expand Down Expand Up @@ -214,23 +217,38 @@ module network 'modules/network.bicep' = if (enablePrivateNetworking) {
}

module aiServices 'modules/ai-foundry/main.bicep' = {
name: take('aiservices-${resourcesName}-deployment', 64)
#disable-next-line no-unnecessary-dependson
dependsOn: [logAnalyticsWorkspace, network] // required due to optional flags that could change dependency
name: take('avm.res.cognitive-services.account.${resourcesName}', 64)
params: {
name: 'ais-${resourcesName}'
location: aiDeploymentsLocation
sku: 'S0'
kind: 'AIServices'
deployments: [modelDeployment]
projectName: 'proj-${resourcesName}'
deployments: [ modelDeployment ]
projectName: 'aifp-${resourcesName}'
projectDescription: 'aifp-${resourcesName}'
logAnalyticsWorkspaceResourceId: enableMonitoring ? logAnalyticsWorkspaceResourceId : ''
privateNetworking: enablePrivateNetworking
? {
virtualNetworkResourceId: network.outputs.vnetResourceId
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
Expand Down Expand Up @@ -307,9 +325,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
Expand Down Expand Up @@ -466,15 +484,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'
Expand All @@ -486,7 +504,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'
Expand Down
3 changes: 3 additions & 0 deletions infra/main.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
},
Expand Down
58 changes: 45 additions & 13 deletions infra/modules/ai-foundry/ai-services.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ param sku string = 'S0'
@description('Optional. Location for all Resources.')
param location string = resourceGroup().location

@description('Optional. Use this parameter to use an existing Cognitive Services resource ID from different resource group')
param azureExistingCognitiveServiceResourceId string = ''

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[]?
Expand Down Expand Up @@ -123,6 +126,13 @@ param managedIdentities managedIdentityAllType?
@description('Optional. Array of deployments about cognitive service accounts to create.')
param deployments deploymentType[]?

// Determine if we should reuse existing Cognitive Services resource
var useExistingCognitiveService = !empty(azureExistingCognitiveServiceResourceId)
var existingCogServiceName = useExistingCognitiveService ? last(split(azureExistingCognitiveServiceResourceId, '/')) : ''
var existingCogServiceRgName = useExistingCognitiveService ? split(azureExistingCognitiveServiceResourceId, '/')[4] : ''
var existingCogServiceSubscriptionId = useExistingCognitiveService ? split(azureExistingCognitiveServiceResourceId, '/')[2] : ''
var existingCogServiceEndpoint = useExistingCognitiveService ? format('https://{0}.cognitiveservices.azure.com/', existingCogServiceName) : ''

var enableReferencedModulesTelemetry = false

var formattedUserAssignedIdentities = reduce(
Expand Down Expand Up @@ -260,7 +270,14 @@ var formattedRoleAssignments = [
})
]

resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' = {
// Reference to existing Cognitive Services account
resource existingCognitiveService 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = if (useExistingCognitiveService) {
name: existingCogServiceName
scope: resourceGroup(existingCogServiceSubscriptionId, existingCogServiceRgName)
}

// Create new Cognitive Services account only if not reusing existing one
resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' = if (!useExistingCognitiveService) {
name: name
kind: kind
identity: identity
Expand Down Expand Up @@ -307,7 +324,7 @@ resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-04-01-previ

@batchSize(1)
resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/deployments@2024-10-01' = [
for (deployment, index) in (deployments ?? []): {
for (deployment, index) in (useExistingCognitiveService ? [] : (deployments ?? [])): {
parent: cognitiveService
name: deployment.?name ?? '${name}-deployments'
properties: {
Expand All @@ -327,7 +344,7 @@ resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/depl

#disable-next-line use-recent-api-versions
resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [
for (diagnosticSetting, index) in (diagnosticSettings ?? []): {
for (diagnosticSetting, index) in (useExistingCognitiveService ? [] : (diagnosticSettings ?? [])): {
name: diagnosticSetting.?name ?? '${name}-diagnosticSettings'
properties: {
storageAccountId: diagnosticSetting.?storageAccountResourceId
Expand All @@ -354,9 +371,9 @@ resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSetti
scope: cognitiveService
}
]

//
module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.11.0' = [
for (privateEndpoint, index) in (privateEndpoints ?? []): {
for (privateEndpoint, index) in (useExistingCognitiveService ? [] : (privateEndpoints ?? [])): {
name: take('${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}', 64)
scope: resourceGroup(
split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2],
Expand Down Expand Up @@ -410,7 +427,7 @@ module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endp
]

resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [
for (roleAssignment, index) in (formattedRoleAssignments ?? []): {
for (roleAssignment, index) in (useExistingCognitiveService ? [] : (formattedRoleAssignments ?? [])): {
name: roleAssignment.?name ?? guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionId)
properties: {
roleDefinitionId: roleAssignment.roleDefinitionId
Expand All @@ -425,26 +442,41 @@ resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignmen
}
]

// Role assignments for existing Cognitive Services from different resource group
module existingCognitiveService_roleAssignments 'br/public:avm/ptn/authorization/resource-role-assignment:0.1.2' = [
for (roleAssignment, i) in (useExistingCognitiveService ? formattedRoleAssignments : []): {
name: 'existing-cog-role-${i}-${take(uniqueString(azureExistingCognitiveServiceResourceId, roleAssignment.roleDefinitionId, roleAssignment.principalId), 8)}'
scope: resourceGroup(existingCogServiceSubscriptionId, existingCogServiceRgName)
params: {
roleDefinitionId: roleAssignment.roleDefinitionId
principalId: roleAssignment.principalId
principalType: roleAssignment.?principalType ?? 'ServicePrincipal'
resourceId: azureExistingCognitiveServiceResourceId
enableTelemetry: enableReferencedModulesTelemetry
}
}
]

@description('The name of the cognitive services account.')
output name string = cognitiveService.name
output name string = useExistingCognitiveService ? existingCogServiceName : cognitiveService.name

@description('The resource ID of the cognitive services account.')
output resourceId string = cognitiveService.id
output resourceId string = useExistingCognitiveService ? azureExistingCognitiveServiceResourceId : cognitiveService.id

@description('The resource group the cognitive services account was deployed into.')
output resourceGroupName string = resourceGroup().name
output resourceGroupName string = useExistingCognitiveService ? existingCogServiceRgName : resourceGroup().name

@description('The service endpoint of the cognitive services account.')
output endpoint string = cognitiveService.properties.endpoint
output endpoint string = useExistingCognitiveService ? existingCogServiceEndpoint : cognitiveService.properties.endpoint

@description('All endpoints available for the cognitive services account, types depends on the cognitive service kind.')
output endpoints endpointType = cognitiveService.properties.endpoints
output endpoints endpointType = useExistingCognitiveService ? {} : cognitiveService.properties.endpoints

@description('The principal ID of the system assigned identity.')
output systemAssignedMIPrincipalId string? = cognitiveService.?identity.?principalId
output systemAssignedMIPrincipalId string? = useExistingCognitiveService ? null : cognitiveService.?identity.?principalId

@description('The location the resource was deployed into.')
output location string = cognitiveService.location
output location string = useExistingCognitiveService ? reference(azureExistingCognitiveServiceResourceId, '2025-04-01-preview', 'Full').location : cognitiveService.location

@description('The private endpoints of the congitive services account.')
output privateEndpoints privateEndpointOutputType[] = [
Expand Down
Loading