Skip to content
Open
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -464,4 +464,4 @@ __pycache__/
data/sample_code/
# Bicep local files
*.local*.bicepparam
*.local*.parameters.json
*.local*.parameters.jsonMYC-SA
1 change: 1 addition & 0 deletions azure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ metadata:
template: multi-agent-custom-automation-engine-solution-accelerator@1.0
requiredVersions:
azd: '>= 1.18.0 != 1.23.9'
bicep: '>= 0.33.0'
hooks:
postdeploy:
windows:
Expand Down
161 changes: 95 additions & 66 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ var deployerInfo = deployer()
var deployingUserPrincipalId = deployerInfo.objectId

// Restricting deployment to only supported Azure OpenAI regions validated with GPT-4o model
@allowed(['australiaeast', 'eastus2', 'francecentral', 'japaneast', 'norwayeast', 'swedencentral', 'uksouth', 'westus'])
@allowed(['eastus2', 'swedencentral', 'westus'])
@metadata({
azd: {
type: 'location'
usageName: [
'OpenAI.GlobalStandard.gpt4.1, 150'
'OpenAI.GlobalStandard.o4-mini, 50'
'OpenAI.GlobalStandard.gpt4.1-mini, 50'
'OpenAI.GlobalStandard.gpt4.1, 80'
'OpenAI.GlobalStandard.o4-mini, 30'
'OpenAI.GlobalStandard.gpt4.1-mini, 30'
]
}
})
@description('Required. Location for all AI service resources. This should be one of the supported Azure AI Service locations.')
@description('Required. Location for all AI service resources. Limited to regions where gpt-4.1, gpt-4.1-mini, and o4-mini are all available as GlobalStandard.')
param azureAiServiceLocation string

@minLength(1)
Expand Down Expand Up @@ -100,14 +100,17 @@ param gptModelDeploymentType string = 'GlobalStandard'
@description('Optional. GPT model deployment type. Defaults to GlobalStandard.')
param gptReasoningModelDeploymentType string = 'GlobalStandard'

@description('Optional. AI model deployment token capacity. Defaults to 50 for optimal performance.')
param gptModelCapacity int = 50
@description('Optional. AI model deployment token capacity (thousands of tokens per minute). Total across all 3 models must not exceed your subscription GlobalStandard quota. Reduce if provisioning fails with InsufficientQuota.')
@minValue(1)
param gptModelCapacity int = 30

@description('Optional. AI model deployment token capacity. Defaults to 150 for optimal performance.')
param gpt4_1ModelCapacity int = 150
@description('Optional. AI model deployment token capacity (thousands of tokens per minute). This is the primary model — allocate the most capacity here.')
@minValue(1)
param gpt4_1ModelCapacity int = 80

@description('Optional. AI model deployment token capacity. Defaults to 50 for optimal performance.')
param gptReasoningModelCapacity int = 50
@description('Optional. AI model deployment token capacity (thousands of tokens per minute). Reasoning model used for complex tasks.')
@minValue(1)
param gptReasoningModelCapacity int = 30

@description('Optional. The tags to apply to all deployed Azure resources.')
param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = {}
Expand All @@ -125,10 +128,10 @@ param enableRedundancy bool = false
param enablePrivateNetworking bool = false

@secure()
@description('Optional. The user name for the administrator account of the virtual machine. Allows to customize credentials if `enablePrivateNetworking` is set to true.')
@description('Required when enablePrivateNetworking is true. The admin username for the jumpbox VM. Must be provided — no default for security.')
param virtualMachineAdminUsername string?

@description('Optional. The password for the administrator account of the virtual machine. Allows to customize credentials if `enablePrivateNetworking` is set to true.')
@description('Required when enablePrivateNetworking is true. The admin password for the jumpbox VM. Must meet Azure complexity requirements (12+ chars, uppercase, lowercase, number, special char). Must be provided — no default for security.')
@secure()
param virtualMachineAdminPassword string?

Expand Down Expand Up @@ -616,8 +619,8 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.17.0' = if (e
computerName: take(virtualMachineResourceName, 15)
osType: 'Windows'
vmSize: virtualMachineSize
adminUsername: virtualMachineAdminUsername ?? 'JumpboxAdminUser'
adminPassword: virtualMachineAdminPassword ?? 'JumpboxAdminP@ssw0rd1234!'
adminUsername: virtualMachineAdminUsername!
adminPassword: virtualMachineAdminPassword!
patchMode: 'AutomaticByPlatform'
bypassPlatformSafetyChecksOnUserSchedule: true
maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId
Expand Down Expand Up @@ -889,6 +892,53 @@ module aiFoundryAiServices 'br:mcr.microsoft.com/bicep/avm/res/cognitive-service
apiProperties: {
//staticsEnabled: false
}
deployments: [] // Deploy models separately via ai-services-deployments.bicep to avoid ETag conflicts
networkAcls: {
defaultAction: 'Allow'
virtualNetworkRules: []
ipRules: []
}
managedIdentities: { userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] } //To create accounts or projects, you must enable a managed identity on your resource
roleAssignments: [
{
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User
principalId: userAssignedIdentity.outputs.principalId
principalType: 'ServicePrincipal'
}
{
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer
principalId: userAssignedIdentity.outputs.principalId
principalType: 'ServicePrincipal'
}
{
roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' // Cognitive Services OpenAI User
principalId: userAssignedIdentity.outputs.principalId
principalType: 'ServicePrincipal'
}
{
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User
principalId: deployingUserPrincipalId
principalType: deployerPrincipalType
}
{
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer
principalId: deployingUserPrincipalId
principalType: deployerPrincipalType
}
]
// WAF aligned configuration for Monitoring
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null
publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled'
// Private endpoints are deployed separately via the aiFoundryPrivateEndpoint module below
privateEndpoints: []
}
}

// Deploy models sequentially after the AI Services account is fully created (avoids ETag conflicts)
module newAiFoundryModelDeployments 'modules/ai-services-deployments.bicep' = if (!useExistingAiFoundryAiProject) {
name: take('module.ai-services-model-deployments.new.${aiFoundryAiServicesResourceName}', 64)
params: {
name: aiFoundryAiServices!.outputs.name
deployments: [
{
name: aiFoundryAiServicesModelDeployment.name
Expand All @@ -898,10 +948,7 @@ module aiFoundryAiServices 'br:mcr.microsoft.com/bicep/avm/res/cognitive-service
version: aiFoundryAiServicesModelDeployment.version
}
raiPolicyName: aiFoundryAiServicesModelDeployment.raiPolicyName
sku: {
name: aiFoundryAiServicesModelDeployment.sku.name
capacity: aiFoundryAiServicesModelDeployment.sku.capacity
}
sku: aiFoundryAiServicesModelDeployment.sku
}
{
name: aiFoundryAiServices4_1ModelDeployment.name
Expand All @@ -911,10 +958,7 @@ module aiFoundryAiServices 'br:mcr.microsoft.com/bicep/avm/res/cognitive-service
version: aiFoundryAiServices4_1ModelDeployment.version
}
raiPolicyName: aiFoundryAiServices4_1ModelDeployment.raiPolicyName
sku: {
name: aiFoundryAiServices4_1ModelDeployment.sku.name
capacity: aiFoundryAiServices4_1ModelDeployment.sku.capacity
}
sku: aiFoundryAiServices4_1ModelDeployment.sku
}
{
name: aiFoundryAiServicesReasoningModelDeployment.name
Expand All @@ -924,51 +968,38 @@ module aiFoundryAiServices 'br:mcr.microsoft.com/bicep/avm/res/cognitive-service
version: aiFoundryAiServicesReasoningModelDeployment.version
}
raiPolicyName: aiFoundryAiServicesReasoningModelDeployment.raiPolicyName
sku: {
name: aiFoundryAiServicesReasoningModelDeployment.sku.name
capacity: aiFoundryAiServicesReasoningModelDeployment.sku.capacity
}
sku: aiFoundryAiServicesReasoningModelDeployment.sku
}
]
networkAcls: {
defaultAction: 'Allow'
virtualNetworkRules: []
ipRules: []
}
managedIdentities: { userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] } //To create accounts or projects, you must enable a managed identity on your resource
roleAssignments: [
{
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d'
principalId: userAssignedIdentity.outputs.principalId
principalType: 'ServicePrincipal'
}
{
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee'
principalId: userAssignedIdentity.outputs.principalId
principalType: 'ServicePrincipal'
}
{
roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' // Cognitive Services OpenAI User
roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd'
principalId: userAssignedIdentity.outputs.principalId
principalType: 'ServicePrincipal'
}
{
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d'
principalId: deployingUserPrincipalId
principalType: deployerPrincipalType
}
{
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee'
principalId: deployingUserPrincipalId
principalType: deployerPrincipalType
}
]
// WAF aligned configuration for Monitoring
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null
publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled'
// Private endpoints are deployed separately via the aiFoundryPrivateEndpoint module below
privateEndpoints: []
}
dependsOn: [aiFoundryAiServices]
}

module aiFoundryPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.8.1' = if (enablePrivateNetworking && !useExistingAiFoundryAiProject) {
Expand Down Expand Up @@ -1449,7 +1480,7 @@ module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = {
}
{
name: 'ENABLE_AUTH'
value: 'false'
value: 'true'
}
{
name: 'TENANT_ID'
Expand Down Expand Up @@ -1689,8 +1720,7 @@ module searchServiceUpdate 'br/public:avm/res/search/search-service:0.11.1' = {

// Enabled the Public access because other services are not able to connect with search search AVM module when public access is disabled

// publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled'
publicNetworkAccess: 'Enabled'
publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled'
networkRuleSet: {
bypass: 'AzureServices'
}
Expand Down Expand Up @@ -1721,26 +1751,24 @@ module searchServiceUpdate 'br/public:avm/res/search/search-service:0.11.1' = {
}
]

//Removing the Private endpoints as we are facing the issue with connecting to search service while comminicating with agents

privateEndpoints: []
// privateEndpoints: enablePrivateNetworking
// ? [
// {
// name: 'pep-search-${solutionSuffix}'
// customNetworkInterfaceName: 'nic-search-${solutionSuffix}'
// privateDnsZoneGroup: {
// privateDnsZoneGroupConfigs: [
// {
// privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.search]!.outputs.resourceId
// }
// ]
// }
// subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0]
// service: 'searchService'
// }
// ]
// : []
privateEndpoints: enablePrivateNetworking
? [
{
name: 'pep-search-${solutionSuffix}'
customNetworkInterfaceName: 'nic-search-${solutionSuffix}'
privateDnsZoneGroup: {
privateDnsZoneGroupConfigs: [
{
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.search]!.outputs.resourceId
}
]
}
subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0]
service: 'searchService'
}
]
: []
publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled'
}
dependsOn: [
searchService
Expand Down Expand Up @@ -1784,6 +1812,7 @@ module keyvault 'br/public:avm/res/key-vault/vault:0.12.1' = {
enableVaultForTemplateDeployment: true
enableRbacAuthorization: true
enableSoftDelete: true
enablePurgeProtection: false
softDeleteRetentionInDays: 7
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : []
// WAF aligned configuration for Private Networking
Expand Down
Loading