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
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# BYO Azure OpenAI AI Foundry Deployment (Private Networking)

This directory contains a single Bicep template (`main.bicep`) that provisions an Azure AI Foundry account with public access disabled, wires it to a private virtual network, and links the account to an existing Azure OpenAI resource using a connection and capability hosts.

## What the template deploys
- **AI Foundry account** (`Microsoft.CognitiveServices/accounts`) with `AIServices` kind, system-assigned identity, and public network access disabled.
- **Virtual network and subnet** sized for private endpoints with network policies disabled to allow Private Link.
- **Private endpoint** to the AI Foundry account plus private DNS zones (`privatelink.services.ai.azure.com`, `privatelink.openai.azure.com`, `privatelink.cognitiveservices.azure.com`) and links to the VNet.
- **Project** inside the Foundry account with a BYO Azure OpenAI connection (`connections@2025-04-01-preview`).
- **Capability hosts** at both account and project scope so the project can use the BYO connection.
- **Sample model deployment** (`gpt-4o-mini`) inside the AI Foundry account for validation.

## Required inputs
Provide the ID of an existing Azure OpenAI resource that resides in a private network-capable region:
```
/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<aoai-account>
```

You may optionally override defaults such as the base account name, project metadata, or VNet address space through parameters.

## Deploy
1. Create or select a resource group in a supported region:
```bash
az group create --name <rg-name> --location <region>
```
2. Deploy the Bicep file, providing the existing Azure OpenAI resource ID. You can use the provided `main.parameters.json` as an example and update the parameter values, or pass them inline:
```bash
az deployment group create \
--resource-group <rg-name> \
--template-file main.bicep \
--parameters existingAoaiResourceId="/subscriptions/<...>/accounts/<...>"
```

## Outputs
The deployment surfaces the Foundry account ID, name, endpoint, project name, and the fully qualified resource ID of the project connection (`projectConnectionName`).

## Notes
- Ensure the private subnet range does not overlap with on-premises or other VNets linked to your environment.
- Deployments from machines outside the private network will not be able to reach the Foundry endpoint unless routed through VPN, ExpressRoute, or a jump host in the VNet.
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
/*
Combined AI Foundry deployment with private networking and BYO Azure OpenAI connection.

Description:
- Creates an AI Foundry account with public network access disabled and private connectivity resources.
- Creates a project with a connection to an existing Azure OpenAI resource.
- Configures account and project capability hosts bound to the connection.
- Deploys a sample GPT-4o model deployment in the AI Foundry account.
*/
param azureDeployName string = utcNow()

@maxLength(9)
@description('Base name for the AI Foundry account. A random suffix is appended to ensure uniqueness.')
param accountBaseName string = 'foundry'

var aiFoundryName = '${accountBaseName}${substring(uniqueString(azureDeployName), 0, 4)}'

@allowed([
'australiaeast'
'canadaeast'
'eastus'
'eastus2'
'francecentral'
'japaneast'
'koreacentral'
'norwayeast'
'polandcentral'
'southindia'
'swedencentral'
'switzerlandnorth'
'uaenorth'
'uksouth'
'westus'
'westus3'
'westeurope'
'southeastasia'
])
@description('The Azure region where the AI Foundry account and related resources will be created.')
param location string = 'eastus'

@description('Name of the project to create within the AI Foundry account.')
param projectName string = '${accountBaseName}${substring(uniqueString(azureDeployName), 0, 4)}-proj'

@description('Display name of the project to create within the AI Foundry account.')
param projectDisplayName string = 'Project Display Name'

@description('Description for the project to create within the AI Foundry account.')
param projectDescription string = 'Sample project provisioned by Bicep.'

@description('Name of the virtual network that will host the private endpoint.')
param vnetName string = 'private-vnet'

@description('Name of the subnet dedicated to private endpoints.')
param peSubnetName string = 'pe-subnet'

@description('Address space for the virtual network.')
param vnetAddressPrefix string = '192.168.0.0/16'

@description('Address prefix for the private endpoint subnet.')
param peSubnetPrefix string = '192.168.0.0/24'

@description('Resource ID of the existing Azure OpenAI resource to connect to the project.')
param existingAoaiResourceId string

var byoAoaiConnectionName string = 'aoaiConnection'
var accountCapabilityHostName string = '${aiFoundryName}-capHost'

// Break down the Azure OpenAI resource ID to extract subscription, resource group, and resource name.
var existingAoaiResourceIdParts = split(existingAoaiResourceId, '/')
var existingAoaiResourceSubscriptionId = existingAoaiResourceIdParts[2]
var existingAoaiResourceGroupName = existingAoaiResourceIdParts[4]
var existingAoaiAccountName = existingAoaiResourceIdParts[8]

// Reference the existing Azure OpenAI resource.
resource existingAoaiResource 'Microsoft.CognitiveServices/accounts@2023-05-01' existing = {
scope: resourceGroup(existingAoaiResourceSubscriptionId, existingAoaiResourceGroupName)
name: existingAoaiAccountName
}

// Create the AI Foundry account with private network access only.
resource account 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' = {
name: aiFoundryName
location: location
kind: 'AIServices'
sku: {
name: 'S0'
}
identity: {
type: 'SystemAssigned'
}
properties: {
allowProjectManagement: true
customSubDomainName: aiFoundryName
disableLocalAuth: false
publicNetworkAccess: 'Disabled'
}
}

// Create a virtual network and subnet that will host private endpoints for the account.
resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
vnetAddressPrefix
]
}
}
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2024-05-01' = {
parent: virtualNetwork
name: peSubnetName
properties: {
addressPrefix: peSubnetPrefix
privateEndpointNetworkPolicies: 'Disabled'
}
}

// Private endpoint configuration for the AI Foundry account.
resource aiAccountPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-05-01' = {
name: '${aiFoundryName}-private-endpoint'
location: location
properties: {
subnet: {
id: subnet.id
}
privateLinkServiceConnections: [
{
name: '${aiFoundryName}-private-link-service-connection'
properties: {
privateLinkServiceId: account.id
groupIds: [
'account'
]
}
}
]
}
}

// Private DNS zones required for the AI Foundry and Azure OpenAI endpoints.
resource aiServicesPrivateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
name: 'privatelink.services.ai.azure.com'
location: 'global'
}

resource openAiPrivateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
name: 'privatelink.openai.azure.com'
location: 'global'
}

resource cognitiveServicesPrivateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
name: 'privatelink.cognitiveservices.azure.com'
location: 'global'
}

// Link each private DNS zone to the new virtual network.
resource aiServicesLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01' = {
parent: aiServicesPrivateDnsZone
location: 'global'
name: 'aiServices-link'
properties: {
virtualNetwork: {
id: virtualNetwork.id
}
registrationEnabled: false
}
}

resource aiOpenAILink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01' = {
parent: openAiPrivateDnsZone
location: 'global'
name: 'aiServicesOpenAI-link'
properties: {
virtualNetwork: {
id: virtualNetwork.id
}
registrationEnabled: false
}
}

resource cognitiveServicesLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01' = {
parent: cognitiveServicesPrivateDnsZone
location: 'global'
name: 'aiServicesCognitiveServices-link'
properties: {
virtualNetwork: {
id: virtualNetwork.id
}
registrationEnabled: false
}
}

// Associate the private endpoint with the DNS zones to enable private name resolution.
resource aiServicesDnsGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2024-05-01' = {
parent: aiAccountPrivateEndpoint
name: '${aiFoundryName}-dns-group'
properties: {
privateDnsZoneConfigs: [
{
name: '${aiFoundryName}-dns-aiserv-config'
properties: {
privateDnsZoneId: aiServicesPrivateDnsZone.id
}
}
{
name: '${aiFoundryName}-dns-openai-config'
properties: {
privateDnsZoneId: openAiPrivateDnsZone.id
}
}
{
name: '${aiFoundryName}-dns-cogserv-config'
properties: {
privateDnsZoneId: cognitiveServicesPrivateDnsZone.id
}
}
]
}
dependsOn: [
aiServicesLink
cognitiveServicesLink
aiOpenAILink
]
}


// Create a project within the AI Foundry account and configure the BYO Azure OpenAI connection.
resource project 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = {
parent: account
name: projectName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
description: projectDescription
displayName: projectDisplayName
}

resource byoAoaiConnection 'connections@2025-04-01-preview' = {
name: byoAoaiConnectionName
properties: {
category: 'AzureOpenAI'
target: existingAoaiResource.properties.endpoint
authType: 'AAD'
metadata: {
ApiType: 'Azure'
ResourceId: existingAoaiResource.id
location: existingAoaiResource.location
}
}
}
}

// Configure capability hosts so the project can leverage the Azure OpenAI connection.
resource accountCapabilityHost 'Microsoft.CognitiveServices/accounts/capabilityHosts@2025-04-01-preview' = {
name: accountCapabilityHostName
parent: account
properties: {
capabilityHostKind: 'Agents'
}
dependsOn: [
project
project::byoAoaiConnection
]
}

resource projectCapabilityHost 'Microsoft.CognitiveServices/accounts/projects/capabilityHosts@2025-04-01-preview' = {
name: '${project.name}-capHost'
parent: project
properties: {
capabilityHostKind: 'Agents'
aiServicesConnections: [
byoAoaiConnectionName
]
}
dependsOn: [
accountCapabilityHost
project::byoAoaiConnection
]
}

output accountId string = account.id
output accountName string = account.name
output accountEndpoint string = account.properties.endpoint
output projectName string = project.name
output projectConnectionName string = resourceId('Microsoft.CognitiveServices/accounts/projects/connections', account.name, project.name, byoAoaiConnectionName)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"accountBaseName": {
"value": "foundry"
},
"location": {
"value": "eastus"
},
"projectName": {
"value": "foundry-proj"
},
"projectDisplayName": {
"value": "Foundry Project"
},
"projectDescription": {
"value": "Sample AI Foundry project deployment."
},
"vnetName": {
"value": "private-vnet"
},
"peSubnetName": {
"value": "pe-subnet"
},
"vnetAddressPrefix": {
"value": "192.168.0.0/16"
},
"peSubnetPrefix": {
"value": "192.168.0.0/24"
},
"existingAoaiResourceId": {
"value": "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<aoai-account>"
}
}
}
Loading