Skip to content

Commit da9f658

Browse files
Merge remote-tracking branch 'origin/AIFoundry-FDPUpdate' into ai-foundry-main-dev-merge
2 parents 4d9dc7a + 152211e commit da9f658

16 files changed

Lines changed: 1591 additions & 301 deletions

File tree

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.2] - 2025-05-13
6+
### Added
7+
- Add new project module leveraging the new cognitive services/projects type
8+
- Add BYO service connections for search, storage and CosmosDB to project (based on feature flag selection)
9+
- new infrastructure drawing
10+
11+
### Changed
12+
- Revise Cognitive Services module to leverage new preview api to leverage new FDP updates
13+
- Update AI Search CMK enforcement value to 'disabled'
14+
- Update and add private endpoints for cognitive services project subtype
15+
- Update and add required roles and scopes to cognitive services and ai search modules
16+
- Update md to show changes
17+
18+
### Deprecated
19+
- Remove the modules deploying AML hub and project.
20+
521

622
## [1.1] - 2025-04-30
723
### Added

README.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,24 @@
44

55
## Overview
66

7-
This is a foundational deployment solution for deploying an AI hub and project into an isolated environment (vNet) within Azure. The deployed features follow Microsoft's Well-Architected Framework [WAF](https://learn.microsoft.com/en-us/azure/well-architected/) to establish an isolated infrastructure for AI Foundry, intended to assist in moving from a Proof of Concept state to a production-ready application.
7+
<span style="font-size: 3em;">🚀</span> **New: Updated deployment to match Foundry release at Build 2025!**
8+
This new update has been tested in the EastUS2 region successfully.
9+
This is a foundational solution for deploying an AI Foundry account ([Cognitive Services accountKind = 'AIServices'](https://review.learn.microsoft.com/en-us/azure/templates/microsoft.cognitiveservices/2025-04-01-preview/accounts?branch=main&pivots=deployment-language-bicep)) and project ([cognitiveServices/projects](https://review.learn.microsoft.com/en-us/azure/templates/microsoft.cognitiveservices/2025-04-01-preview/accounts/projects?branch=main&pivots=deployment-language-bicep)) into an isolated environment (vNet) within Azure. The deployed features follow Microsoft's Well-Architected Framework [WAF](https://learn.microsoft.com/en-us/azure/well-architected/) to establish an isolated infrastructure for AI Foundry, intended to assist in moving from a Proof of Concept state to a production-ready application.
810

9-
This template leverages Azure Verified Modules (AVM) and the Azure Developer CLI (AZD) to provision a WAF-aligned infrastructure for AI application development. This infrastructure includes AI Foundry elements, a virtual network (VNET), private endpoints, Key Vault, a storage account, and additional, optional WAF-aligned resources (such as Cosmos DB and SQL Server) that can be leveraged with Foundry developed projects.
11+
This template leverages Azure Verified Modules (AVM) and the Azure Developer CLI (AZD) to provision a WAF-aligned infrastructure for AI application development. This infrastructure includes AI Foundry elements, a virtual network (VNET), private endpoints, Key Vault, a storage account, and additional, optional WAF-aligned resources (such as AI Search, Cosmos DB and SQL Server) that can be leveraged with Foundry developed projects.
1012

1113
The following deployment automates our recommended configuration to protect your data and resources; using Microsoft Entra ID role-based access control, a managed network, and private endpoints. We recommend disabling public network access for Azure OpenAI resources, Azure AI Search resources, and storage accounts (which will occur when deploying those optional services within this workflow). Using selected networks with IP rules isn't supported because the services' IP addresses are dynamic.
1214

13-
AI Foundry has two network isolation aspects, this repository will automate:
14-
1. Configuring the network isolation of the Azure AI Foundry hub and project managed compute (compute instance, serverless compute, managed online endpoint) [Configure Managed Network](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/configure-managed-network)
15-
2. Configuring the virtual network, private end points and private link services to isolate resources to connect to the hub and project in a secure way. [Secure Data Playground](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/secure-data-playground)
15+
This repository will automate:
16+
1. Configuring the virtual network, private end points and private link services to isolate resources connecting to the account and project in a secure way. [Secure Data Playground](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/secure-data-playground)
17+
2. Deploying and configuring the network isolation of the Azure AI Foundry account and project sub-resource within the virtual network, and with all services configured behind private end points.
18+
1619

1720

1821
## Architecture
1922
The diagram below illustrates the capabilities included in the template.
2023

21-
![Network Isolation Infrastructure](./img/Architecture/Deploy-AI-App-in-Prod-Architecture_final.png)
24+
![Network Isolation Infrastructure](./img/Architecture/FDParch.png)
2225

2326
| Diagram Step | Description |
2427
| ------------- | ------------- |
@@ -31,12 +34,12 @@ The diagram below illustrates the capabilities included in the template.
3134
## Features
3235

3336
### What solutions does this enable?
34-
- Deploys AI hub and AI project into a virtual network with all dependent services connected via private end points.
37+
- Deploys an AI Foundry account and project leveraging the latest AI Foundry updates announced at Build 2025, into a virtual network with all dependent services connected via private end points.
3538

3639
- Configures AI Foundry, adhering to the best practices outlined in the Well Architected Framework.
3740

3841
- Provides the ability to [add additional Azure services during deployment](docs/add_additional_services.md), configured to connect via isolation to enrich your AI project.
39-
(API Management, CosmosDB, Azure SQL DB)
42+
(AI Search, API Management, CosmosDB, Azure SQL DB)
4043

4144
- <span style="font-size: 3em;">🚀</span> **New**:
4245
Offers ability to [start with an existing Azure AI Project](docs/transfer_project_connections.md) which will provision dependent Azure resources based on the Project's established connections within AI Foundry.
@@ -49,8 +52,7 @@ Offers ability to [start with an existing Azure AI Project](docs/transfer_projec
4952
3. The solution ensures secure access to the private VNET through a jump-box VM with Azure Bastion. By default, Bastion does not require an inbound NSG rule for network traffic. However, if your environment enforces specific policy rules, you can resolve access issues by entering your machine's IP address in the `allowedIpAddress` parameter when prompted during deployment. If not specified, all IP addresses are allowed to connect to Azure Bastion.
5053
4. If deploying from your [local environment](docs/local_environment_steps.md), install the [Azure CLI (AZ)](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) and the [Azure Developer CLI (AZD)](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/install-azd?tabs=winget-windows%2Cbrew-mac%2Cscript-linux&pivots=os-windows).
5154
5. If deploying via [GitHub Codespaces](docs/github_code_spaces_steps.md) - requires the user to be on a GitHub Team or Enterprise Cloud plan.
52-
6. If leveraging [One-click deployment](#quick-deploy).
53-
7. If leveraging [GitHub Actions](docs/github_actions_steps.md).
55+
6. If leveraging [GitHub Actions](docs/github_actions_steps.md).
5456

5557
### Check Azure OpenAI Quota Availability
5658

@@ -80,7 +82,7 @@ For additional documentation of the default enabled services of this solution ac
8082
QUICK DEPLOY
8183
</h2>
8284

83-
| [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/microsoft/Deploy-Your-AI-Application-In-Production) | [![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/Deploy-Your-AI-Application-In-Production) |
85+
| [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/microsoft/Deploy-Your-AI-Application-In-Production/tree/feature/1RP) | [![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/Deploy-Your-AI-Application-In-Production) |
8486
|---|---|
8587
[Steps to deploy with GitHub Codespaces](docs/github_code_spaces_steps.md)
8688

@@ -110,7 +112,7 @@ This template has [Managed Identity](https://learn.microsoft.com/entra/identity/
110112

111113
## Resources
112114

113-
- [Azure AI Foundry documentation](https://learn.microsoft.com/en-us/azure/ai-studio/)
115+
- [Azure AI Foundry documentation](https://learn.microsoft.com/en-us/azure/ai-foundry/)
114116
- [Azure Well Architecture Framework documentation](https://learn.microsoft.com/en-us/azure/well-architected/)
115117
- [Azure OpenAI Service - Documentation, quickstarts, API reference - Azure AI services | Microsoft Learn](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data)
116118
- [Azure AI Content Understanding documentation](https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/)

img/Architecture/Architecture.png

-352 KB
Binary file not shown.

img/Architecture/FDParch.png

127 KB
Loading

infra/main.bicep

Lines changed: 39 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ param translatorEnabled bool
8282
@description('Whether to include Azure Document Intelligence in the deployment.')
8383
param documentIntelligenceEnabled bool
8484

85+
@description('Optional. A collection of rules governing the accessibility from specific network locations.')
86+
param networkAcls object ={
87+
defaultAction: 'Deny'
88+
bypass: 'AzureServices' // ✅ Allows trusted Microsoft services
89+
// virtualNetworkRules: [
90+
// {
91+
// id: networkIsolation ? network.outputs.vmSubnetName : ''
92+
// ignoreMissingVnetServiceEndpoint: true
93+
// }
94+
// ]
95+
}
96+
97+
@description('Name of the first project')
98+
param projectName string = '${name}proj'
99+
85100
var defaultTags = {
86101
'azd-env-name': name
87102
}
@@ -170,7 +185,7 @@ module containerRegistry 'modules/containerRegistry.bicep' = if (acrEnabled) {
170185
module storageAccount 'modules/storageAccount.bicep' = {
171186
name: take('${name}-storage-account-deployment', 64)
172187
params: {
173-
name: 'st${name}${resourceToken}'
188+
storageName: 'st${name}${resourceToken}'
174189
location: location
175190
networkIsolation: networkIsolation
176191
virtualNetworkResourceId: networkIsolation ? network.outputs.virtualNetworkId : ''
@@ -190,7 +205,7 @@ module storageAccount 'modules/storageAccount.bicep' = {
190205
}
191206
], searchEnabled ? [
192207
{
193-
principalId: aiSearch.outputs.systemAssignedMIPrincipalId
208+
principalId: searchEnabled ? aiSearch.outputs.systemAssignedMIPrincipalId : ''
194209
principalType: 'ServicePrincipal'
195210
roleDefinitionIdOrName: 'Storage Blob Data Contributor'
196211
}
@@ -206,6 +221,7 @@ module cognitiveServices 'modules/cognitive-services/main.bicep' = {
206221
resourceToken: resourceToken
207222
location: location
208223
networkIsolation: networkIsolation
224+
networkAcls: networkAcls
209225
virtualNetworkResourceId: networkIsolation ? network.outputs.virtualNetworkId : ''
210226
virtualNetworkSubnetResourceId: networkIsolation ? network.outputs.vmSubnetId : ''
211227
logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace.outputs.resourceId
@@ -221,6 +237,21 @@ module cognitiveServices 'modules/cognitive-services/main.bicep' = {
221237
}
222238
}
223239

240+
// // Add the new FDP cognitive services module
241+
module project 'modules/ai-foundry-project/main.bicep' = {
242+
name: '${name}prj'
243+
params: {
244+
cosmosDBname: cosmosDbEnabled? cosmosDb.outputs.cosmosDBname : ''
245+
cosmosDbEnabled: cosmosDbEnabled
246+
searchEnabled: searchEnabled
247+
name: projectName
248+
location: location
249+
storageName: storageAccount.outputs.storageName
250+
aiServicesName: cognitiveServices.outputs.aiServicesName
251+
nameFormatted: searchEnabled ? aiSearch.outputs.name : ''
252+
}
253+
}
254+
224255
module aiSearch 'modules/aisearch.bicep' = if (searchEnabled) {
225256
name: take('${name}-ai-search-deployment', 64)
226257
params: {
@@ -230,6 +261,7 @@ module aiSearch 'modules/aisearch.bicep' = if (searchEnabled) {
230261
virtualNetworkResourceId: networkIsolation ? network.outputs.virtualNetworkId : ''
231262
virtualNetworkSubnetResourceId: networkIsolation ? network.outputs.vmSubnetId : ''
232263
logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace.outputs.resourceId
264+
userObjectId: userObjectId
233265
roleAssignments: union(empty(userObjectId) ? [] : [
234266
{
235267
principalId: userObjectId
@@ -259,7 +291,7 @@ module virtualMachine './modules/virtualMachine.bicep' = if (networkIsolation)
259291
vmNicName: toLower('nic-vm-${name}-jump')
260292
vmSize: vmSize
261293
vmSubnetId: network.outputs.vmSubnetId
262-
storageAccountName: storageAccount.outputs.name
294+
storageAccountName: storageAccount.outputs.storageName
263295
storageAccountResourceGroup: resourceGroup().name
264296
imagePublisher: 'MicrosoftWindowsDesktop'
265297
imageOffer: 'Windows-11'
@@ -282,72 +314,6 @@ module virtualMachine './modules/virtualMachine.bicep' = if (networkIsolation)
282314
dependsOn: networkIsolation ? [storageAccount] : []
283315
}
284316

285-
module aiHub 'modules/ai-foundry/hub.bicep' = {
286-
name: take('${name}-ai-hub-deployment', 64)
287-
params: {
288-
name: 'hub-${name}'
289-
location: location
290-
networkIsolation: networkIsolation
291-
virtualNetworkResourceId: networkIsolation ? network.outputs.virtualNetworkId : ''
292-
virtualNetworkSubnetResourceId: networkIsolation ? network.outputs.vmSubnetId : ''
293-
logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace.outputs.resourceId
294-
appInsightsResourceId: applicationInsights.outputs.resourceId
295-
containerRegistryResourceId: acrEnabled ? containerRegistry.outputs.resourceId : null
296-
keyVaultResourceId: keyvault.outputs.resourceId
297-
storageAccountResourceId: storageAccount.outputs.resourceId
298-
roleAssignments:empty(userObjectId) ? [] : [
299-
{
300-
roleDefinitionIdOrName: 'f6c7c914-8db3-469d-8ca1-694a8f32e121' // ML Data Scientist Role
301-
principalId: userObjectId
302-
principalType: 'User'
303-
}
304-
]
305-
connections: concat(
306-
cognitiveServices.outputs.connections,
307-
connections,
308-
searchEnabled ? [
309-
{
310-
name: aiSearch.outputs.name
311-
value: null
312-
category: 'CognitiveSearch'
313-
target: 'https://${aiSearch.outputs.name}.search.windows.net/'
314-
connectionProperties: {
315-
authType: 'AAD'
316-
}
317-
isSharedToAll: true
318-
metadata: {
319-
ApiType: 'Azure'
320-
ResourceId: aiSearch.outputs.resourceId
321-
}
322-
}] : [])
323-
tags: allTags
324-
}
325-
}
326-
327-
module aiProject 'modules/ai-foundry/project.bicep' = {
328-
name: take('${name}-ai-project-deployment', 64)
329-
params: {
330-
name: 'proj-${name}'
331-
location: location
332-
hubResourceId: aiHub.outputs.resourceId
333-
networkIsolation: networkIsolation
334-
logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace.outputs.resourceId
335-
roleAssignments: union(empty(userObjectId) ? [] : [
336-
{
337-
roleDefinitionIdOrName: 'f6c7c914-8db3-469d-8ca1-694a8f32e121' // ML Data Scientist Role
338-
principalId: userObjectId
339-
principalType: 'User'
340-
}
341-
], [
342-
{
343-
roleDefinitionIdOrName: 'f6c7c914-8db3-469d-8ca1-694a8f32e121' // ML Data Scientist Role
344-
principalId: cognitiveServices.outputs.aiServicesSystemAssignedMIPrincipalId
345-
principalType: 'ServicePrincipal'
346-
}
347-
])
348-
tags: allTags
349-
}
350-
}
351317

352318
module apim 'modules/apim.bicep' = if (apiManagementEnabled) {
353319
name: take('${name}-apim-deployment', 64)
@@ -400,18 +366,18 @@ import { connectionType } from 'br/public:avm/res/machine-learning-services/work
400366
output AZURE_KEY_VAULT_NAME string = keyvault.outputs.name
401367
output AZURE_AI_SERVICES_NAME string = cognitiveServices.outputs.aiServicesName
402368
output AZURE_AI_SEARCH_NAME string = searchEnabled ? aiSearch.outputs.name : ''
403-
output AZURE_AI_HUB_NAME string = aiHub.outputs.name
404-
output AZURE_AI_PROJECT_NAME string = aiHub.outputs.name
369+
output AZURE_AI_HUB_NAME string = cognitiveServices.outputs.aiServicesName
370+
output AZURE_AI_PROJECT_NAME string = project.outputs.projectName
405371
output AZURE_BASTION_NAME string = networkIsolation ? network.outputs.bastionName : ''
406372
output AZURE_VM_RESOURCE_ID string = networkIsolation ? virtualMachine.outputs.id : ''
407373
output AZURE_VM_USERNAME string = servicesUsername
408374
output AZURE_APP_INSIGHTS_NAME string = applicationInsights.outputs.name
409375
output AZURE_CONTAINER_REGISTRY_NAME string = acrEnabled ? containerRegistry.outputs.name : ''
410376
output AZURE_LOG_ANALYTICS_WORKSPACE_NAME string = logAnalyticsWorkspace.outputs.name
411-
output AZURE_STORAGE_ACCOUNT_NAME string = storageAccount.outputs.name
377+
output AZURE_STORAGE_ACCOUNT_NAME string = storageAccount.outputs.storageName
412378
output AZURE_API_MANAGEMENT_NAME string = apiManagementEnabled ? apim.outputs.name : ''
413379
output AZURE_VIRTUAL_NETWORK_NAME string = networkIsolation ? network.outputs.virtualNetworkName : ''
414380
output AZURE_VIRTUAL_NETWORK_SUBNET_NAME string =networkIsolation ? network.outputs.vmSubnetName : ''
415381
output AZURE_SQL_SERVER_NAME string = sqlServerEnabled ? sqlServer.outputs.name : ''
416382
output AZURE_SQL_SERVER_USERNAME string = sqlServerEnabled ? servicesUsername : ''
417-
output AZURE_COSMOS_ACCOUNT_NAME string = cosmosDbEnabled ? cosmosDb.outputs.name : ''
383+
output AZURE_COSMOS_ACCOUNT_NAME string = cosmosDbEnabled ? cosmosDb.outputs.cosmosDBname : ''

0 commit comments

Comments
 (0)