Skip to content
Merged
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
1 change: 1 addition & 0 deletions docs/CustomizingAzdParameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ By default this template will use the environment name as the prefix to prevent
| `AZURE_ENV_OPENAI_LOCATION` | string | `swedencentral` | Specifies the region for OpenAI resource deployment. |
| `AZURE_ENV_MODEL_DEPLOYMENT_TYPE` | string | `GlobalStandard` | Defines the deployment type for the AI model (e.g., Standard, GlobalStandard). |
| `AZURE_ENV_MODEL_NAME` | string | `gpt-4o` | Specifies the name of the GPT model to be deployed. |
| `AZURE_ENV_FOUNDRY_PROJECT_ID` | string | `<Existing Workspace Id>` | Set this if you want to reuse an AI Foundry Project instead of creating a new one. |
| `AZURE_ENV_MODEL_VERSION` | string | `2024-08-06` | Version of the GPT model to be used for deployment. |
| `AZURE_ENV_IMAGETAG` | string | `latest` | Docker image tag used for container deployments. |
| `AZURE_ENV_ENABLE_TELEMETRY` | bool | `true` | Enables telemetry for monitoring and diagnostics. |
Expand Down
167 changes: 30 additions & 137 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ metadata description = 'This module contains the resources required to deploy th
@description('Set to true if you want to deploy WAF-aligned infrastructure.')
param useWafAlignedArchitecture bool

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

@description('Optional. The prefix to add in the default names given to all deployed Azure resources.')
@maxLength(19)
param solutionPrefix string = 'macae${uniqueString(deployer().objectId, deployer().tenantId, subscription().subscriptionId, resourceGroup().id)}'
Expand Down Expand Up @@ -45,10 +48,6 @@ param gptModelCapacity int = 150
@description('Set the image tag for the container images used in the solution. Default is "latest".')
param imageTag string = 'latest'

// @description('Set this if you want to deploy to a different region than the resource group. Otherwise, it will use the resource group location by default.')
// param AZURE_LOCATION string=''
// param solutionLocation string = empty(AZURE_LOCATION) ? resourceGroup().location

@description('Optional. The tags to apply to all deployed Azure resources.')
param tags object = {
app: solutionPrefix
Expand Down Expand Up @@ -233,32 +232,6 @@ param webSiteConfiguration webSiteConfigurationType = {
environmentResourceId: null //Default value set on module configuration
}

//
// Add your parameters here
//

// ============== //
// Resources //
// ============== //

/* #disable-next-line no-deployments-resources
resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) {
name: '46d3xbcp.[[REPLACE WITH TELEMETRY IDENTIFIER]].${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'
}
}
}
}
} */

// ========== Log Analytics Workspace ========== //
// WAF best practices for Log Analytics: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-log-analytics
Expand Down Expand Up @@ -595,8 +568,6 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:0.6.1' = if (vi
name: 'administration'
addressPrefix: '10.0.0.32/27'
networkSecurityGroupResourceId: networkSecurityGroupAdministration.outputs.resourceId
//defaultOutboundAccess: false TODO: check this configuration for a more restricted outbound access
//natGatewayResourceId: natGateway.outputs.resourceId
}
{
// For Azure Bastion resources deployed on or after November 2, 2021, the minimum AzureBastionSubnet size is /26 or larger (/25, /24, etc.).
Expand All @@ -610,7 +581,6 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:0.6.1' = if (vi
// https://learn.microsoft.com/en-us/azure/container-apps/networking?tabs=workload-profiles-env%2Cazure-cli#custom-vnw-configuration
name: 'containers'
addressPrefix: '10.0.2.0/23' //subnet of size /23 is required for container app
//defaultOutboundAccess: false TODO: check this configuration for a more restricted outbound access
delegation: 'Microsoft.App/environments'
networkSecurityGroupResourceId: networkSecurityGroupContainers.outputs.resourceId
privateEndpointNetworkPolicies: 'Disabled'
Expand Down Expand Up @@ -640,9 +610,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:0.6.1' = if (virtualN
disableCopyPaste: false
enableFileCopy: false
enableIpConnect: true
//enableKerberos: bastionConfiguration.?enableKerberos
enableShareableLink: true
//scaleUnits: bastionConfiguration.?scaleUnits
}
}

Expand All @@ -664,8 +632,6 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.13.0' = if (v
nicConfigurations: [
{
name: 'nic-${virtualMachineResourceName}'
//networkSecurityGroupResourceId: virtualMachineConfiguration.?nicConfigurationConfiguration.networkSecurityGroupResourceId
//nicSuffix: 'nic-${virtualMachineResourceName}'
diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }]
ipConfigurations: [
{
Expand All @@ -691,18 +657,13 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.13.0' = if (v
diskSizeGB: 128
caching: 'ReadWrite'
}
//patchMode: virtualMachineConfiguration.?patchMode
osType: 'Windows'
encryptionAtHost: false //The property 'securityProfile.encryptionAtHost' is not valid because the 'Microsoft.Compute/EncryptionAtHost' feature is not enabled for this subscription.
zone: 0
extensionAadJoinConfig: {
enabled: true
typeHandlerVersion: '1.0'
}
// extensionMonitoringAgentConfig: {
// enabled: true
// }
// maintenanceConfigurationResourceId: virtualMachineConfiguration.?maintenanceConfigurationResourceId
}
}

Expand Down Expand Up @@ -750,17 +711,20 @@ var aiFoundryAiServicesModelDeployment = {
raiPolicyName: 'Microsoft.Default'
}

module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0' = if (aiFoundryAIservicesEnabled) {
module aiFoundryAiServices 'modules/account/main.bicep' = if (aiFoundryAIservicesEnabled) {
name: take('avm.res.cognitive-services.account.${aiFoundryAiServicesResourceName}', 64)
params: {
name: aiFoundryAiServicesResourceName
tags: aiFoundryAiServicesConfiguration.?tags ?? tags
location: aiFoundryAiServicesConfiguration.?location ?? aiDeploymentsLocation
enableTelemetry: enableTelemetry
projectName: 'aifp-${solutionPrefix}'
projectDescription: 'aifp-${solutionPrefix}'
existingFoundryProjectResourceId: existingFoundryProjectResourceId
diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }]
sku: aiFoundryAiServicesConfiguration.?sku ?? 'S0'
kind: 'AIServices'
disableLocalAuth: false //Should be set to true for WAF aligned configuration
disableLocalAuth: true //Should be set to true for WAF aligned configuration
customSubDomainName: aiFoundryAiServicesResourceName
apiProperties: {
//staticsEnabled: false
Expand All @@ -769,9 +733,13 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0'
managedIdentities: {
systemAssigned: true
}
//publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled'
//publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled'
publicNetworkAccess: 'Enabled' //TODO: connection via private endpoint is not working from containers network. Change this when fixed
publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled'
networkAcls: {
bypass: 'AzureServices'
defaultAction: (virtualNetworkEnabled) ? 'Deny' : 'Allow'
}


privateEndpoints: virtualNetworkEnabled
? ([
{
Expand All @@ -787,18 +755,6 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0'
}
])
: []
// roleAssignments: [
// // {
// // principalId: userAssignedIdentity.outputs.principalId
// // principalType: 'ServicePrincipal'
// // roleDefinitionIdOrName: 'Cognitive Services OpenAI User'
// // }
// {
// principalId: containerApp.outputs.?systemAssignedMIPrincipalId!
// principalType: 'ServicePrincipal'
// roleDefinitionIdOrName: 'Cognitive Services OpenAI User'
// }
// ]
deployments: aiFoundryAiServicesConfiguration.?deployments ?? [
{
name: aiFoundryAiServicesModelDeployment.name
Expand All @@ -819,76 +775,34 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0'

// AI Foundry: AI Project
// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai
// var aiFoundryAiProjectEnabled = aiFoundryAiProjectConfiguration.?enabled ?? true
var aiFoundryAiProjectName = aiFoundryAiProjectConfiguration.?name ?? 'aifp-${solutionPrefix}'
var aiProjectDescription = 'AI Foundry Project'

resource aiServices 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = {
name: aiFoundryAiServicesResourceName
dependsOn:[
aiFoundryAiServices
]
}

resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = {
parent: aiServices
name: aiFoundryAiProjectName
location: aiFoundryAiProjectConfiguration.?location ?? aiDeploymentsLocation
identity: {
type: 'SystemAssigned'
}
properties: {
description: aiProjectDescription
displayName: aiFoundryAiProjectName
}
}

resource aiUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: '53ca6127-db72-4b80-b1b0-d745d6d5456d'
}

resource aiUserAccessProj 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(containerApp.name, aiFoundryProject.id, aiUser.id)
scope: aiFoundryProject
properties: {
roleDefinitionId: aiUser.id
principalId: containerApp.outputs.?systemAssignedMIPrincipalId!
}
}
var useExistingResourceId = !empty(existingFoundryProjectResourceId)

resource aiUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(containerApp.name, aiServices.id, aiUser.id)
scope: aiServices
properties: {
module Newroles './modules/role.bicep' = if(!useExistingResourceId){
params: {
name: 'new-${guid(containerApp.name, aiFoundryAiServices.outputs.resourceId, aiUser.id)}'
roleDefinitionId: aiUser.id
principalId: containerApp.outputs.?systemAssignedMIPrincipalId!
aiUserid: aiUser.id
aiServiceName: aiFoundryAiServices.outputs.name
}
scope: resourceGroup(subscription().subscriptionId, resourceGroup().name)
}

resource aiDeveloper 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: '64702f94-c441-49e6-a78b-ef80e0188fee'
}

resource aiDeveloperAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(containerApp.name, aiServices.id, aiDeveloper.id)
scope: aiFoundryProject
properties: {
roleDefinitionId: aiDeveloper.id
principalId: containerApp.outputs.?systemAssignedMIPrincipalId!
}
}

resource cognitiveServiceOpenAIUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd'
}

resource cognitiveServiceOpenAIUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(containerApp.name, aiServices.id, cognitiveServiceOpenAIUser.id)
scope: aiServices
properties: {
roleDefinitionId: cognitiveServiceOpenAIUser.id
module Existingroles './modules/role.bicep' = if(useExistingResourceId){
params: {
name: 'reuse-${guid(containerApp.name, aiFoundryAiServices.outputs.aiProjectInfo.resourceId, aiUser.id)}'
roleDefinitionId: aiUser.id
principalId: containerApp.outputs.?systemAssignedMIPrincipalId!
aiUserid: aiUser.id
aiServiceName: aiFoundryAiServices.outputs.name
}
scope: resourceGroup( split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4])
}

// ========== Cosmos DB ========== //
Expand Down Expand Up @@ -966,7 +880,6 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (co
'EnableServerless'
]
sqlRoleAssignmentsPrincipalIds: [
//userAssignedIdentity.outputs.principalId
containerApp.outputs.?systemAssignedMIPrincipalId
]
sqlRoleDefinitions: [
Expand Down Expand Up @@ -1003,13 +916,6 @@ module containerAppEnvironment 'modules/container-app-environment.bicep' = if (c
subnetResourceId: virtualNetworkEnabled
? containerAppEnvironmentConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[3] ?? ''
: ''
//aspireDashboardEnabled: !virtualNetworkEnabled
// vnetConfiguration: virtualNetworkEnabled
// ? {
// internal: false
// infrastructureSubnetId: containerAppEnvironmentConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[3] ?? ''
// }
// : {}
}
}

Expand Down Expand Up @@ -1117,7 +1023,7 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container
}
{
name: 'AZURE_AI_AGENT_ENDPOINT'
value: aiFoundryProject.properties.endpoints['AI Foundry API']
value: aiFoundryAiServices.outputs.aiProjectInfo.apiEndpoint
}
{
name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME'
Expand Down Expand Up @@ -1189,19 +1095,6 @@ module webSite 'br/public:avm/res/web/site:0.15.1' = if (webSiteEnabled) {
@description('The default url of the website to connect to the Multi-Agent Custom Automation Engine solution.')
output webSiteDefaultHostname string = webSite.outputs.defaultHostname

// @description('The name of the resource.')
// output name string = <Resource>.name

// @description('The location the resource was deployed into.')
// output location string = <Resource>.location

// ================ //
// Definitions //
// ================ //
//
// Add your User-defined-types here, if any
//

@export()
@description('The type for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource configuration.')
type logAnalyticsWorkspaceConfigurationType = {
Expand Down
3 changes: 3 additions & 0 deletions infra/main.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
"gptModelCapacity": {
"value": "${AZURE_ENV_MODEL_CAPACITY}"
},
"existingFoundryProjectResourceId": {
"value": "${AZURE_ENV_FOUNDRY_PROJECT_ID}"
},
"imageTag": {
"value": "${AZURE_ENV_IMAGE_TAG}"
},
Expand Down
Loading
Loading