Skip to content

Commit a9c504b

Browse files
committed
Revert template 15 to upstream and add template 19 (hybrid private resources)
- Reverted 15-private-network-standard-agent-setup to match upstream/main exactly - Added 19-hybrid-private-resources-agent-setup: hybrid architecture with public AI Services endpoint and private backend resources (AI Search, Cosmos DB, Storage) - Template 19 enables portal-based agent testing while keeping data resources private - Includes TESTING-GUIDE.md, test scripts, and architecture diagrams in template 19
1 parent 2319877 commit a9c504b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+7098
-837
lines changed

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/TESTING-GUIDE.md

Lines changed: 0 additions & 599 deletions
This file was deleted.

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/azuredeploy.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
"_generator": {
66
"name": "bicep",
77
"version": "0.39.26.7824",
8-
"templateHash": "3024624923779287280"
8+
"templateHash": "16616047834738415823"
99
}
1010
},
1111
"parameters": {
1212
"location": {
1313
"type": "string",
14-
"defaultValue": "eastus2",
14+
"defaultValue": "eastus",
1515
"allowedValues": [
1616
"westus",
1717
"eastus",
@@ -50,7 +50,7 @@
5050
},
5151
"modelName": {
5252
"type": "string",
53-
"defaultValue": "gpt-4o",
53+
"defaultValue": "gpt-4.1",
5454
"metadata": {
5555
"description": "The name of the model you want to deploy"
5656
}
@@ -64,7 +64,7 @@
6464
},
6565
"modelVersion": {
6666
"type": "string",
67-
"defaultValue": "2024-11-20",
67+
"defaultValue": "2025-04-14",
6868
"metadata": {
6969
"description": "The version of your model"
7070
}

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/main.bicep

Lines changed: 53 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,18 @@ Standard Setup Network Secured Steps for main.bicep
3030
'switzerlandnorth'
3131
'norwayeast'
3232
])
33-
param location string = 'eastus2'
33+
param location string = 'eastus'
3434

3535
@description('Name for your AI Services resource.')
3636
param aiServices string = 'aiservices'
3737

3838
// Model deployment parameters
3939
@description('The name of the model you want to deploy')
40-
param modelName string = 'gpt-4o'
40+
param modelName string = 'gpt-4.1'
4141
@description('The provider of your model')
4242
param modelFormat string = 'OpenAI'
4343
@description('The version of your model')
44-
param modelVersion string = '2024-11-20'
44+
param modelVersion string = '2025-04-14'
4545
@description('The sku of your model deployment')
4646
param modelSkuName string = 'GlobalStandard'
4747
@description('The tokens per minute (TPM) of your model deployment')
@@ -71,9 +71,6 @@ param agentSubnetName string = 'agent-subnet'
7171
@description('The name of Private Endpoint subnet to create new or existing subnet for private endpoints')
7272
param peSubnetName string = 'pe-subnet'
7373

74-
@description('The name of MCP subnet for user-deployed Container Apps (e.g., MCP servers)')
75-
param mcpSubnetName string = 'mcp-subnet'
76-
7774
//Existing standard Agent required resources
7875
@description('Existing Virtual Network name Resource ID')
7976
param existingVnetResourceId string = ''
@@ -87,19 +84,13 @@ param agentSubnetPrefix string = ''
8784
@description('Address prefix for the private endpoint subnet')
8885
param peSubnetPrefix string = ''
8986

90-
@description('Address prefix for the MCP subnet. The default value is 192.168.2.0/24.')
91-
param mcpSubnetPrefix string = ''
92-
9387
@description('The AI Search Service full ARM Resource ID. This is an optional field, and if not provided, the resource will be created.')
9488
param aiSearchResourceId string = ''
9589
@description('The AI Storage Account full ARM Resource ID. This is an optional field, and if not provided, the resource will be created.')
9690
param azureStorageAccountResourceId string = ''
9791
@description('The Cosmos DB Account full ARM Resource ID. This is an optional field, and if not provided, the resource will be created.')
9892
param azureCosmosDBAccountResourceId string = ''
9993

100-
@description('The Microsoft Fabric Workspace full ARM Resource ID. This is an optional field for Fabric private link connectivity.')
101-
param fabricWorkspaceResourceId string = ''
102-
10394
//New Param for resource group of Private DNS zones
10495
//@description('Optional: Resource group containing existing private DNS zones. If specified, DNS zones will not be created.')
10596
//param existingDnsZonesResourceGroup string = ''
@@ -108,11 +99,10 @@ param fabricWorkspaceResourceId string = ''
10899
param existingDnsZones object = {
109100
'privatelink.services.ai.azure.com': ''
110101
'privatelink.openai.azure.com': ''
111-
'privatelink.cognitiveservices.azure.com': ''
112-
'privatelink.search.windows.net': ''
113-
'privatelink.blob.core.windows.net': ''
114-
'privatelink.documents.azure.com': ''
115-
'privatelink.analysis.windows.net': ''
102+
'privatelink.cognitiveservices.azure.com': ''
103+
'privatelink.search.windows.net': ''
104+
'privatelink.blob.core.windows.net': ''
105+
'privatelink.documents.azure.com': ''
116106
}
117107

118108
@description('Zone Names for Validation of existing Private Dns Zones')
@@ -123,9 +113,9 @@ param dnsZoneNames array = [
123113
'privatelink.search.windows.net'
124114
'privatelink.blob.core.windows.net'
125115
'privatelink.documents.azure.com'
126-
'privatelink.analysis.windows.net'
127116
]
128117

118+
129119
var projectName = toLower('${firstProjectName}${uniqueSuffix}')
130120
var cosmosDBName = toLower('${aiServices}${uniqueSuffix}cosmosdb')
131121
var aiSearchName = toLower('${aiServices}${uniqueSuffix}search')
@@ -137,6 +127,7 @@ var searchPassedIn = aiSearchResourceId != ''
137127
var cosmosPassedIn = azureCosmosDBAccountResourceId != ''
138128
var existingVnetPassedIn = existingVnetResourceId != ''
139129

130+
140131
var acsParts = split(aiSearchResourceId, '/')
141132
var aiSearchServiceSubscriptionId = searchPassedIn ? acsParts[2] : subscription().subscriptionId
142133
var aiSearchServiceResourceGroupName = searchPassedIn ? acsParts[4] : resourceGroup().name
@@ -168,11 +159,9 @@ module vnet 'modules-network-secured/network-agent-vnet.bicep' = {
168159
existingVnetResourceGroupName: vnetResourceGroupName
169160
agentSubnetName: agentSubnetName
170161
peSubnetName: peSubnetName
171-
mcpSubnetName: mcpSubnetName
172162
vnetAddressPrefix: vnetAddressPrefix
173163
agentSubnetPrefix: agentSubnetPrefix
174164
peSubnetPrefix: peSubnetPrefix
175-
mcpSubnetPrefix: mcpSubnetPrefix
176165
existingVnetSubscriptionId: vnetSubscriptionId
177166
}
178167
}
@@ -231,20 +220,18 @@ module aiDependencies 'modules-network-secured/standard-dependent-resources.bice
231220
// Cosmos DB Account
232221
cosmosDBResourceId: azureCosmosDBAccountResourceId
233222
cosmosDBExists: validateExistingResources.outputs.cosmosDBExists
234-
}
223+
}
235224
}
236225

237226
resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' existing = {
238227
name: aiDependencies.outputs.azureStorageName
239228
scope: resourceGroup(azureStorageSubscriptionId, azureStorageResourceGroupName)
240229
}
241230

231+
242232
resource aiSearch 'Microsoft.Search/searchServices@2023-11-01' existing = {
243233
name: aiDependencies.outputs.aiSearchName
244-
scope: resourceGroup(
245-
aiDependencies.outputs.aiSearchServiceSubscriptionId,
246-
aiDependencies.outputs.aiSearchServiceResourceGroupName
247-
)
234+
scope: resourceGroup(aiDependencies.outputs.aiSearchServiceSubscriptionId, aiDependencies.outputs.aiSearchServiceResourceGroupName)
248235
}
249236

250237
resource cosmosDB 'Microsoft.DocumentDB/databaseAccounts@2024-11-15' existing = {
@@ -259,32 +246,31 @@ resource cosmosDB 'Microsoft.DocumentDB/databaseAccounts@2024-11-15' existing =
259246
// 3. Links private DNS zones to the VNet for name resolution
260247
// 4. Configures network policies to restrict access to private endpoints only
261248
module privateEndpointAndDNS 'modules-network-secured/private-endpoint-and-dns.bicep' = {
262-
name: '${uniqueSuffix}-private-endpoint'
263-
params: {
264-
aiAccountName: aiAccount.outputs.accountName // AI Services to secure
265-
aiSearchName: aiDependencies.outputs.aiSearchName // AI Search to secure
266-
storageName: aiDependencies.outputs.azureStorageName // Storage to secure
267-
cosmosDBName: aiDependencies.outputs.cosmosDBName
268-
fabricWorkspaceResourceId: fabricWorkspaceResourceId // Microsoft Fabric workspace (optional)
269-
vnetName: vnet.outputs.virtualNetworkName // VNet containing subnets
270-
peSubnetName: vnet.outputs.peSubnetName // Subnet for private endpoints
271-
suffix: uniqueSuffix // Unique identifier
272-
vnetResourceGroupName: vnet.outputs.virtualNetworkResourceGroup
273-
vnetSubscriptionId: vnet.outputs.virtualNetworkSubscriptionId // Subscription ID for the VNet
274-
cosmosDBSubscriptionId: cosmosDBSubscriptionId // Subscription ID for Cosmos DB
275-
cosmosDBResourceGroupName: cosmosDBResourceGroupName // Resource Group for Cosmos DB
276-
aiSearchSubscriptionId: aiSearchServiceSubscriptionId // Subscription ID for AI Search Service
277-
aiSearchResourceGroupName: aiSearchServiceResourceGroupName // Resource Group for AI Search Service
278-
storageAccountResourceGroupName: azureStorageResourceGroupName // Resource Group for Storage Account
279-
storageAccountSubscriptionId: azureStorageSubscriptionId // Subscription ID for Storage Account
280-
existingDnsZones: existingDnsZones
281-
}
282-
dependsOn: [
283-
aiSearch // Ensure AI Search exists
284-
storage // Ensure Storage exists
285-
cosmosDB // Ensure Cosmos DB exists
249+
name: '${uniqueSuffix}-private-endpoint'
250+
params: {
251+
aiAccountName: aiAccount.outputs.accountName // AI Services to secure
252+
aiSearchName: aiDependencies.outputs.aiSearchName // AI Search to secure
253+
storageName: aiDependencies.outputs.azureStorageName // Storage to secure
254+
cosmosDBName:aiDependencies.outputs.cosmosDBName
255+
vnetName: vnet.outputs.virtualNetworkName // VNet containing subnets
256+
peSubnetName: vnet.outputs.peSubnetName // Subnet for private endpoints
257+
suffix: uniqueSuffix // Unique identifier
258+
vnetResourceGroupName: vnet.outputs.virtualNetworkResourceGroup
259+
vnetSubscriptionId: vnet.outputs.virtualNetworkSubscriptionId // Subscription ID for the VNet
260+
cosmosDBSubscriptionId: cosmosDBSubscriptionId // Subscription ID for Cosmos DB
261+
cosmosDBResourceGroupName: cosmosDBResourceGroupName // Resource Group for Cosmos DB
262+
aiSearchSubscriptionId: aiSearchServiceSubscriptionId // Subscription ID for AI Search Service
263+
aiSearchResourceGroupName: aiSearchServiceResourceGroupName // Resource Group for AI Search Service
264+
storageAccountResourceGroupName: azureStorageResourceGroupName // Resource Group for Storage Account
265+
storageAccountSubscriptionId: azureStorageSubscriptionId // Subscription ID for Storage Account
266+
existingDnsZones: existingDnsZones
267+
}
268+
dependsOn: [
269+
aiSearch // Ensure AI Search exists
270+
storage // Ensure Storage exists
271+
cosmosDB // Ensure Cosmos DB exists
286272
]
287-
}
273+
}
288274

289275
/*
290276
Creates a new project (sub-resource of the AI Services account)
@@ -313,10 +299,10 @@ module aiProject 'modules-network-secured/ai-project-identity.bicep' = {
313299
accountName: aiAccount.outputs.accountName
314300
}
315301
dependsOn: [
316-
privateEndpointAndDNS
317-
cosmosDB
318-
aiSearch
319-
storage
302+
privateEndpointAndDNS
303+
cosmosDB
304+
aiSearch
305+
storage
320306
]
321307
}
322308

@@ -338,8 +324,8 @@ module storageAccountRoleAssignment 'modules-network-secured/azure-storage-accou
338324
projectPrincipalId: aiProject.outputs.projectPrincipalId
339325
}
340326
dependsOn: [
341-
storage
342-
privateEndpointAndDNS
327+
storage
328+
privateEndpointAndDNS
343329
]
344330
}
345331

@@ -383,13 +369,13 @@ module addProjectCapabilityHost 'modules-network-secured/add-project-capability-
383369
projectCapHost: projectCapHost
384370
}
385371
dependsOn: [
386-
aiSearch // Ensure AI Search exists
387-
storage // Ensure Storage exists
388-
cosmosDB
389-
privateEndpointAndDNS
390-
cosmosAccountRoleAssignments
391-
storageAccountRoleAssignment
392-
aiSearchRoleAssignments
372+
aiSearch // Ensure AI Search exists
373+
storage // Ensure Storage exists
374+
cosmosDB
375+
privateEndpointAndDNS
376+
cosmosAccountRoleAssignments
377+
storageAccountRoleAssignment
378+
aiSearchRoleAssignments
393379
]
394380
}
395381

@@ -415,9 +401,10 @@ module cosmosContainerRoleAssignments 'modules-network-secured/cosmos-container-
415401
cosmosAccountName: aiDependencies.outputs.cosmosDBName
416402
projectWorkspaceId: formatProjectWorkspaceId.outputs.projectWorkspaceIdGuid
417403
projectPrincipalId: aiProject.outputs.projectPrincipalId
404+
418405
}
419-
dependsOn: [
420-
addProjectCapabilityHost
421-
storageContainersRoleAssignment
406+
dependsOn: [
407+
addProjectCapabilityHost
408+
storageContainersRoleAssignment
422409
]
423410
}

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/main.bicepparam

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
using './main.bicep'
22

3-
param location = 'norwayeast'
4-
param aiServices = 'djetchev'
3+
param location = 'eastus2'
4+
param aiServices = 'aiservices'
55
param modelName = 'gpt-4o'
66
param modelFormat = 'OpenAI'
77
param modelVersion = '2024-11-20'
8-
param modelSkuName = 'Standard'
9-
param modelCapacity = 1
8+
param modelSkuName = 'GlobalStandard'
9+
param modelCapacity = 30
1010
param firstProjectName = 'project'
1111
param projectDescription = 'A project for the AI Foundry account with network secured deployed Agent'
1212
param displayName = 'project'
@@ -25,10 +25,10 @@ param azureCosmosDBAccountResourceId = ''
2525
param existingDnsZones = {
2626
'privatelink.services.ai.azure.com': ''
2727
'privatelink.openai.azure.com': ''
28-
'privatelink.cognitiveservices.azure.com': ''
29-
'privatelink.search.windows.net': ''
30-
'privatelink.blob.core.windows.net': ''
31-
'privatelink.documents.azure.com': ''
28+
'privatelink.cognitiveservices.azure.com': ''
29+
'privatelink.search.windows.net': ''
30+
'privatelink.blob.core.windows.net': ''
31+
'privatelink.documents.azure.com': ''
3232
}
3333

3434
//DNSZones names for validating if they exist
@@ -41,6 +41,7 @@ param dnsZoneNames = [
4141
'privatelink.documents.azure.com'
4242
]
4343

44+
4445
// Network configuration (behavior depends on `existingVnetResourceId`)
4546
//
4647
// - NEW VNet (existingVnetResourceId is empty):
@@ -64,3 +65,4 @@ param dnsZoneNames = [
6465
param vnetAddressPrefix = ''
6566
param agentSubnetPrefix = ''
6667
param peSubnetPrefix = ''
68+

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/modules-network-secured/cosmos-container-role-assignments.bicep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var roleDefinitionId = resourceId(
1919
'00000000-0000-0000-0000-000000000002'
2020
)
2121

22-
var accountScope = '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.DocumentDB/databaseAccounts/${cosmosAccountName}'
22+
var accountScope = '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.DocumentDB/databaseAccounts/${cosmosAccountName}/dbs/enterprise_memory'
2323

2424
resource containerRoleAssignmentUserContainer 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = {
2525
parent: cosmosAccount

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/modules-network-secured/existing-vnet.bicep

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This module works with existing virtual networks and required subnets.
1313
- Private endpoint subnet for secure connectivity
1414
*/
1515

16+
1617
@description('The name of the existing virtual network')
1718
param vnetName string
1819

@@ -28,24 +29,17 @@ param agentSubnetName string = 'agent-subnet'
2829
@description('The name of Private Endpoint subnet')
2930
param peSubnetName string = 'pe-subnet'
3031

31-
@description('The name of MCP subnet for user-deployed Container Apps')
32-
param mcpSubnetName string = 'mcp-subnet'
33-
3432
@description('Address prefix for the agent subnet (only needed if creating new subnet)')
3533
param agentSubnetPrefix string = ''
3634

3735
@description('Address prefix for the private endpoint subnet (only needed if creating new subnet)')
3836
param peSubnetPrefix string = ''
3937

40-
@description('Address prefix for the MCP subnet (only needed if creating new subnet)')
41-
param mcpSubnetPrefix string = ''
42-
4338
// Get the address space (array of CIDR strings)
4439
var vnetAddressSpace = existingVNet.properties.addressSpace.addressPrefixes[0]
4540

4641
var agentSubnetSpaces = empty(agentSubnetPrefix) ? cidrSubnet(vnetAddressSpace, 24, 0) : agentSubnetPrefix
4742
var peSubnetSpaces = empty(peSubnetPrefix) ? cidrSubnet(vnetAddressSpace, 24, 1) : peSubnetPrefix
48-
var mcpSubnetSpaces = empty(mcpSubnetPrefix) ? cidrSubnet(vnetAddressSpace, 24, 2) : mcpSubnetPrefix
4943

5044
// Reference the existing virtual network
5145
resource existingVNet 'Microsoft.Network/virtualNetworks@2024-05-01' existing = {
@@ -84,32 +78,11 @@ module peSubnet 'subnet.bicep' = {
8478
}
8579
}
8680

87-
// Create the MCP subnet for user-deployed Container Apps
88-
module mcpSubnet 'subnet.bicep' = {
89-
name: 'mcp-subnet-${uniqueString(deployment().name, mcpSubnetName)}'
90-
scope: resourceGroup(vnetResourceGroupName)
91-
params: {
92-
vnetName: vnetName
93-
subnetName: mcpSubnetName
94-
addressPrefix: mcpSubnetSpaces
95-
delegations: [
96-
{
97-
name: 'Microsoft.App/environments'
98-
properties: {
99-
serviceName: 'Microsoft.App/environments'
100-
}
101-
}
102-
]
103-
}
104-
}
105-
10681
// Output variables
10782
output peSubnetName string = peSubnetName
10883
output agentSubnetName string = agentSubnetName
109-
output mcpSubnetName string = mcpSubnetName
11084
output agentSubnetId string = '${existingVNet.id}/subnets/${agentSubnetName}'
11185
output peSubnetId string = '${existingVNet.id}/subnets/${peSubnetName}'
112-
output mcpSubnetId string = '${existingVNet.id}/subnets/${mcpSubnetName}'
11386
output virtualNetworkName string = existingVNet.name
11487
output virtualNetworkId string = existingVNet.id
11588
output virtualNetworkResourceGroup string = vnetResourceGroupName

0 commit comments

Comments
 (0)