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
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ languages:
![Best Practice Check](https://azurequickstartsservice.blob.core.windows.net/badges/quickstarts/microsoft.azure-ai-agent-service/network-secured-agent/BestPracticeResult.svg)
![Cred Scan Check](https://azurequickstartsservice.blob.core.windows.net/badges/quickstarts/microsoft.azure-ai-agent-service/network-secured-agent/CredScanResult.svg)

![Bicep Version](https://azurequickstartsservice.blob.core.windows.net/badges/quickstarts/microsoft.azure-ai-agent-service/network-secured-agent-thread/BicepVersion.svg)
![Bicep Version](https://azurequickstartsservice.blob.core.windows.net/badges/quickstarts/microsoft.azure-ai-agent-service/basic-agent-keys/BicepVersion.svg)

[![Deploy To Azure](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazure.svg?sanitize=true)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazureai-samples%2Fmain%2Fscenarios%2FAgents%2Fsetup%2Fnetwork-secured-agent-thread-storage%2Fazuredeploy.json)

Expand Down Expand Up @@ -57,7 +57,10 @@ To find your discovery_url, run the CLI command:
```az ml workspace show -n {project_name} --resource-group {resource_group_name} --query discovery_url```
Customer needs to login to Azure subscription via Azure CLI and set the environment variables


In case Azure Funtion Tool required, select from dropdown or edit in bicep
```
azureFunctionToolSupport=Enabled
```
## Architecture Overview

### Network Security Design
Expand All @@ -72,12 +75,14 @@ The deployment creates an isolated network environment:
- AI Services
- AI Search
- Key Vault
- Storage Account
- Storage Account Blob
- Storage Account Queue(Only created for Azure Function tool)
- Cosmos DB

- **Private DNS Zones**
- privatelink.azureml.ms
- privatelink.search.windows.net
- privatelonk.queue.core.windows.net
- privatelink.blob.core.windows.net
- privatelink.documents.azure.com

Expand All @@ -97,7 +102,8 @@ The deployment creates an isolated network environment:
- Azure AI Services
- Azure AI Search
- Key Vault
- Storage Account
- Storage Account Blob
- Storage Account Queue(Only created for Azure Function tool)
- Cosmos DB Account

## Security Features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"_generator": {
"name": "bicep",
"version": "0.33.93.31351",
"templateHash": "11033492472783042104"
"templateHash": "6189989562818270199"
}
},
"parameters": {
Expand Down Expand Up @@ -227,6 +227,17 @@
"description": "The Cosmos DB Account full ARM Resource ID. This is an optional field, and if not provided, the resource will be created."
}
},
"azureFunctionToolSupport": {
"type": "string",
"defaultValue": "Disabled",
"allowedValues": [
"Enabled",
"Disabled"
],
"metadata": {
"description": "Specifies if supporting resources for the Azure Function Tools should be created. This is only required if you are using the Azure Function Tools."
}
},
"userAssignedIdentityDefaultName": {
"type": "string",
"defaultValue": "[format('secured-agents-identity-{0}', parameters('uniqueSuffix'))]",
Expand All @@ -248,7 +259,8 @@
"cosmosParts": "[split(parameters('cosmosDBResourceId'), '/')]",
"cosmosDBSubscriptionId": "[if(variables('cosmosExists'), variables('cosmosParts')[2], subscription().subscriptionId)]",
"cosmosDBResourceGroupName": "[if(variables('cosmosExists'), variables('cosmosParts')[4], resourceGroup().name)]",
"cosmosDBAccountName": "[if(variables('cosmosExists'), variables('cosmosParts')[8], variables('cosmosDBName'))]"
"cosmosDBAccountName": "[if(variables('cosmosExists'), variables('cosmosParts')[8], variables('cosmosDBName'))]",
"azureFunctionToolSupported": "[equals(parameters('azureFunctionToolSupport'), 'Enabled')]"
},
"resources": [
{
Expand Down Expand Up @@ -525,6 +537,9 @@
"cosmosDBExists": {
"value": "[not(empty(parameters('cosmosDBResourceId')))]"
},
"azureFunctionToolSupported": {
"value": "[variables('azureFunctionToolSupported')]"
},
"cosmosDBName": {
"value": "[variables('cosmosDBAccountName')]"
},
Expand Down Expand Up @@ -563,7 +578,7 @@
"_generator": {
"name": "bicep",
"version": "0.33.93.31351",
"templateHash": "13503356786023840518"
"templateHash": "12245658005145867857"
}
},
"parameters": {
Expand All @@ -587,6 +602,10 @@
"type": "bool",
"defaultValue": false
},
"azureFunctionToolSupported": {
"type": "bool",
"defaultValue": false
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
Expand Down Expand Up @@ -716,6 +735,33 @@
"storageParts": "[if(parameters('storageExists'), split(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '/'), split(resourceId('Microsoft.Storage/storageAccounts', variables('storageNameCleaned')), '/'))]"
},
"resources": [
{
"condition": "[and(not(parameters('storageExists')), parameters('azureFunctionToolSupported'))]",
"type": "Microsoft.Storage/storageAccounts/queueServices/queues",
"apiVersion": "2022-05-01",
"name": "[format('{0}/{1}/{2}', variables('storageNameCleaned'), 'default', 'input-queue')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageNameCleaned'), 'default')]"
]
},
{
"condition": "[and(not(parameters('storageExists')), parameters('azureFunctionToolSupported'))]",
"type": "Microsoft.Storage/storageAccounts/queueServices/queues",
"apiVersion": "2022-05-01",
"name": "[format('{0}/{1}/{2}', variables('storageNameCleaned'), 'default', 'output-queue')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/queueServices', variables('storageNameCleaned'), 'default')]"
]
},
{
"condition": "[and(not(parameters('storageExists')), parameters('azureFunctionToolSupported'))]",
"type": "Microsoft.Storage/storageAccounts/queueServices",
"apiVersion": "2022-05-01",
"name": "[format('{0}/{1}', variables('storageNameCleaned'), 'default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageNameCleaned'))]"
]
},
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2023-07-31-preview",
Expand Down Expand Up @@ -1480,6 +1526,9 @@
},
"cosmosDBResourceGroup": {
"value": "[variables('cosmosDBResourceGroupName')]"
},
"azureFunctionToolSupported": {
"value": "[variables('azureFunctionToolSupported')]"
}
},
"template": {
Expand All @@ -1489,7 +1538,7 @@
"_generator": {
"name": "bicep",
"version": "0.33.93.31351",
"templateHash": "2815470915491127245"
"templateHash": "1489959358682641210"
}
},
"parameters": {
Expand Down Expand Up @@ -1561,6 +1610,13 @@
"metadata": {
"description": "Name of the Customer Hub Workspace"
}
},
"azureFunctionToolSupported": {
"type": "bool",
"defaultValue": false,
"metadata": {
"description": "Flag indicating whether azure function tools are supported and backing resources need to be created."
}
}
},
"resources": [
Expand Down Expand Up @@ -1633,15 +1689,15 @@
{
"type": "Microsoft.Network/privateEndpoints",
"apiVersion": "2024-05-01",
"name": "[format('{0}-private-endpoint', parameters('storageName'))]",
"name": "[format('{0}-blob-private-endpoint', parameters('storageName'))]",
"location": "[resourceGroup().location]",
"properties": {
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('cxSubnetName'))]"
},
"privateLinkServiceConnections": [
{
"name": "[format('{0}-private-link-service-connection', parameters('storageName'))]",
"name": "[format('{0}-blob-private-link-service-connection', parameters('storageName'))]",
"properties": {
"privateLinkServiceId": "[parameters('aiStorageId')]",
"groupIds": [
Expand All @@ -1652,6 +1708,29 @@
]
}
},
{
"condition": "[parameters('azureFunctionToolSupported')]",
"type": "Microsoft.Network/privateEndpoints",
"apiVersion": "2024-05-01",
"name": "[format('{0}-queue-private-endpoint', parameters('storageName'))]",
"location": "[resourceGroup().location]",
"properties": {
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('cxSubnetName'))]"
},
"privateLinkServiceConnections": [
{
"name": "[format('{0}-queue-private-link-service-connection', parameters('storageName'))]",
"properties": {
"privateLinkServiceId": "[parameters('aiStorageId')]",
"groupIds": [
"queue"
]
}
}
]
}
},
{
"type": "Microsoft.Network/privateEndpoints",
"apiVersion": "2024-05-01",
Expand Down Expand Up @@ -1894,10 +1973,17 @@
"name": "[format('privatelink.blob.{0}', environment().suffixes.storage)]",
"location": "global"
},
{
"condition": "[parameters('azureFunctionToolSupported')]",
"type": "Microsoft.Network/privateDnsZones",
"apiVersion": "2020-06-01",
"name": "[format('privatelink.queue.{0}', environment().suffixes.storage)]",
"location": "global"
},
{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2024-06-01",
"name": "[format('{0}/{1}', format('privatelink.blob.{0}', environment().suffixes.storage), format('storage-{0}-link', parameters('suffix')))]",
"name": "[format('{0}/{1}', format('privatelink.blob.{0}', environment().suffixes.storage), format('storage-blob-{0}-link', parameters('suffix')))]",
"location": "global",
"properties": {
"virtualNetwork": {
Expand All @@ -1909,14 +1995,30 @@
"[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.blob.{0}', environment().suffixes.storage))]"
]
},
{
"condition": "[parameters('azureFunctionToolSupported')]",
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2024-06-01",
"name": "[format('{0}/{1}', format('privatelink.queue.{0}', environment().suffixes.storage), format('storage-queue-{0}-link', parameters('suffix')))]",
"location": "global",
"properties": {
"virtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]"
},
"registrationEnabled": false
},
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.queue.{0}', environment().suffixes.storage))]"
]
},
{
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
"apiVersion": "2024-05-01",
"name": "[format('{0}/{1}', format('{0}-private-endpoint', parameters('storageName')), format('{0}-dns-group', parameters('storageName')))]",
"name": "[format('{0}/{1}', format('{0}-blob-private-endpoint', parameters('storageName')), format('{0}-blob-dns-group', parameters('storageName')))]",
"properties": {
"privateDnsZoneConfigs": [
{
"name": "[format('{0}-dns-config', parameters('storageName'))]",
"name": "[format('{0}-blob-dns-config', parameters('storageName'))]",
"properties": {
"privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.blob.{0}', environment().suffixes.storage))]"
}
Expand All @@ -1925,7 +2027,27 @@
},
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.blob.{0}', environment().suffixes.storage))]",
"[resourceId('Microsoft.Network/privateEndpoints', format('{0}-private-endpoint', parameters('storageName')))]"
"[resourceId('Microsoft.Network/privateEndpoints', format('{0}-blob-private-endpoint', parameters('storageName')))]"
]
},
{
"condition": "[parameters('azureFunctionToolSupported')]",
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
"apiVersion": "2024-05-01",
"name": "[format('{0}/{1}', format('{0}-queue-private-endpoint', parameters('storageName')), format('{0}-queue-dns-group', parameters('storageName')))]",
"properties": {
"privateDnsZoneConfigs": [
{
"name": "[format('{0}-queue-dns-config', parameters('storageName'))]",
"properties": {
"privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.queue.{0}', environment().suffixes.storage))]"
}
}
]
},
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.queue.{0}', environment().suffixes.storage))]",
"[resourceId('Microsoft.Network/privateEndpoints', format('{0}-queue-private-endpoint', parameters('storageName')))]"
]
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ param aiSearchServiceName string = ''
@description('The Cosmos DB Account full ARM Resource ID. This is an optional field, and if not provided, the resource will be created.')
param cosmosDBResourceId string = ''

@description('Specifies if supporting resources for the Azure Function Tools should be created. This is only required if you are using the Azure Function Tools.')
@allowed([
'Enabled'
'Disabled'
])
param azureFunctionToolSupport string = 'Disabled'

// @description('The Ai Storage Account name. This is an optional field, and if not provided, the resource will be created.The resource should exist in same resource group')
// param aiStorageAccountName string = ''
Expand Down Expand Up @@ -173,6 +179,8 @@ var cosmosParts = split(cosmosDBResourceId, '/')
var cosmosDBSubscriptionId = cosmosExists ? cosmosParts[2] : subscription().subscriptionId
var cosmosDBResourceGroupName = cosmosExists ? cosmosParts[4] : resourceGroup().name
var cosmosDBAccountName = cosmosExists ? cosmosParts[8] : cosmosDBName
var azureFunctionToolSupported = (azureFunctionToolSupport == 'Enabled')

// Create Virtual Network and Subnets
module vnet 'modules-network-secured/networking/vnet.bicep' = {
name: '${name}-${uniqueSuffix}--vnet'
Expand Down Expand Up @@ -203,6 +211,7 @@ module aiDependencies 'modules-network-secured/network-secured-dependent-resourc
aiServicesExists: !empty(aiServiceAccountName)
aiSearchExists: !empty(aiSearchServiceName)
cosmosDBExists: !empty(cosmosDBResourceId)
azureFunctionToolSupported: azureFunctionToolSupported
cosmosDBName: cosmosDBAccountName
cosmosDBSubscription: cosmosDBSubscriptionId
cosmosDBResourceGroup: cosmosDBResourceGroupName
Expand Down Expand Up @@ -294,6 +303,7 @@ module privateEndpointAndDNS 'modules-network-secured/private-endpoint-and-dns.b
cosmosDBName: aiDependencies.outputs.cosmosDBName // Cosmos DB name
cosmosDBSubscription: cosmosDBSubscriptionId // Cosmos DB subscription ID
cosmosDBResourceGroup: cosmosDBResourceGroupName // Cosmos DB resource group name
azureFunctionToolSupported: azureFunctionToolSupported // Flag for Azure Function Tools support
}
dependsOn: [
aiServices // Ensure AI Services exist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ param keyvaultExists bool = false
param aiServicesExists bool = false
param aiSearchExists bool = false
param cosmosDBExists bool = false
param azureFunctionToolSupported bool = false

@description('Azure region of the deployment')
param location string = resourceGroup().location
Expand Down Expand Up @@ -272,6 +273,18 @@ resource defaultStorage 'Microsoft.Storage/storageAccounts@2022-05-01' = if(!sto
}
allowSharedKeyAccess: false // Enforce Azure AD authentication
}

resource queueServices 'queueServices' = if (azureFunctionToolSupported) {
name: 'default'

resource azureFunctionInputQueue 'queues' = {
name: 'input-queue'
}

resource azureFunctionOutputQueue 'queues' = {
name: 'output-queue'
}
}
}

/* -------------------------------------------- Role Assignments -------------------------------------------- */
Expand Down
Loading
Loading