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
12 changes: 12 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
/samples/python/foundry-local/ @microsoft-foundry/foundry-local
/samples/rust/foundry-local/ @microsoft-foundry/foundry-local

#### Partner / external collaborator sample areas #######################################################
# Partners are outside collaborators (not org members). Each entry is the source of truth for that
# partner. Update alongside step 3 of the onboarding process in docs/external-contributions.md.
#
# Format:
# # <Partner name> — onboarded: YYYY-MM-DD — partner: @<partner-github> — dri: @<dri-github>
# /samples/<language>/<partner-area>/ @<dri-github>
#
# Mistral AI — add entry here once DRI and sample paths are confirmed:
# # Mistral AI — onboarded: 2026-06-22 — partner: @peymanmohajerian — dri: @truptiparkar7
# /samples/python/mistral/ @FILL_IN

#### files referenced in docs (DO NOT EDIT, except for Docs team!!!) ##########################################
/infrastructure/infrastructure-setup-bicep/01-connections/connection-key-vault.bicep @microsoft-foundry/AI-Platform-Docs
/infrastructure/infrastructure-setup-bicep/05-custom-policy-definitions/deny-disallowed-connections.json @microsoft-foundry/AI-Platform-Docs
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ override.tf.json
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
*tfplan*

# Ignore CLI configuration files
.terraformrc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,19 @@ az group delete --name <your-resource-group> --yes --no-wait
- Format: From `modelFormat` parameter
- Version: From `modelVersion` parameter

Azure Monitor (Application Insights & Log Analytics)
- Log Analytics Workspace: Microsoft.OperationalInsights/workspaces
- SKU: PerGB2018
- Retention: 30 days
- Application Insights: Microsoft.Insights/components
- Kind: web
- Linked to Log Analytics workspace
- Public ingestion disabled (reached privately via AMPLS)
- Azure Monitor Private Link Scope (AMPLS): microsoft.insights/privateLinkScopes
- Access mode: PrivateOnly ingestion, Open query
- Scoped resources: Application Insights + Log Analytics
- Enables hosted agents to export telemetry via private network

### Network Security Design

This implementation utilizes a BYO VNet (Bring Your Own Virtual Network) approach with subnet delegation. Within your virtual network, two subnets are created: one delegated for agent workloads and one for private endpoints.
Expand All @@ -360,6 +373,7 @@ A private endpoint ensures secure, internal-only connectivity to the AI Services
| Private Link Resource Type | Sub Resource | Private DNS Zone Name | Public DNS Zone Forwarders |
|----------------------------|--------------|------------------------|-----------------------------|
| **Microsoft Foundry** | account | `privatelink.cognitiveservices.azure.com`<br>`privatelink.openai.azure.com`<br>`privatelink.services.ai.azure.com` | `cognitiveservices.azure.com`<br>`openai.azure.com`<br>`services.ai.azure.com` |
| **Azure Monitor (AMPLS)** | azuremonitor | `privatelink.monitor.azure.com`<br>`privatelink.oms.opinsights.azure.com`<br>`privatelink.ods.opinsights.azure.com`<br>`privatelink.agentsvc.azure-automation.net` | `monitor.azure.com`<br>`oms.opinsights.azure.com`<br>`ods.opinsights.azure.com`<br>`agentsvc.azure-automation.net` |

### Authentication & Authorization

Expand All @@ -380,6 +394,8 @@ A private endpoint ensures secure, internal-only connectivity to the AI Services
modules-network-secured/
├── ai-account-identity.bicep # AI Services account with network injection
├── add-project-capability-host.bicep # Basic capability host (no BYO connections)
├── application-insights.bicep # Workspace-based Application Insights for agent tracing
├── monitor-private-link-scope.bicep # Azure Monitor Private Link Scope (AMPLS) for private telemetry ingestion
├── network-agent-vnet.bicep # VNet router (new or existing)
├── vnet.bicep # New VNet creation
├── existing-vnet.bicep # Existing VNet integration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ param existingDnsZones object = {
'privatelink.azurecr.io': ''
}

@description('Object mapping Azure Monitor private DNS zone names to the resource group of an existing zone, or empty string to create it. Use to bring your own centralized Private DNS Zones (e.g. an Azure Landing Zone connectivity subscription) for agent tracing.')
param existingMonitorDnsZones object = {
'privatelink.monitor.azure.com': ''
'privatelink.oms.opinsights.azure.com': ''
'privatelink.ods.opinsights.azure.com': ''
'privatelink.agentsvc.azure-automation.net': ''
}

@description('Zone Names for Validation of existing Private Dns Zones')
param dnsZoneNames array = [
'privatelink.services.ai.azure.com'
Expand Down Expand Up @@ -221,6 +229,37 @@ module acr 'modules-network-secured/container-registry.bicep' = if (enableContai
]
}

// Application Insights for hosted-agent tracing (this template ships none). Creates a
// workspace-based Application Insights and connects it to the account so the agent exports traces.
module applicationInsights 'modules-network-secured/application-insights.bicep' = {
name: 'app-insights-${uniqueSuffix}-deployment'
params: {
location: location
suffix: uniqueSuffix
aiAccountName: aiAccount.outputs.accountName
disablePublicIngestion: true
}
}

// Private trace ingestion path (Azure Monitor Private Link Scope) so an in-VNet agent's traces
// reach Application Insights over the private link rather than the (disabled) public endpoint.
module monitorPrivateLink 'modules-network-secured/monitor-private-link-scope.bicep' = {
name: 'monitor-pls-${uniqueSuffix}-deployment'
params: {
location: location
suffix: uniqueSuffix
appInsightsId: applicationInsights.outputs.appInsightsId
logAnalyticsId: applicationInsights.outputs.logAnalyticsId
vnetId: vnet.outputs.virtualNetworkId
peSubnetId: vnet.outputs.peSubnetId
existingDnsZones: existingMonitorDnsZones
dnsZonesSubscriptionId: resolvedDnsZonesSubscriptionId
}
dependsOn: [
privateEndpointAndDNS
]
}

/*
Step 4: Create a Project
- Sub-resource of the AI Services account
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
Application Insights Module
---------------------------
This module creates workspace-based Application Insights for agent tracing with:
1. Log Analytics workspace
2. Application Insights component (private ingestion for network-secured templates)
3. Connection on the Foundry account so agents export OpenTelemetry traces here
*/

@description('Azure region for the tracing resources.')
param location string

@description('Suffix for unique resource names (the template uniqueSuffix).')
param suffix string

@description('Name of the Foundry (AI Services) account to connect Application Insights to.')
param aiAccountName string

@description('When true, disable public ingestion (reach Application Insights privately via AMPLS). Set false for public templates.')
param disablePublicIngestion bool = true

@description('Name of the Log Analytics workspace to create.')
param logAnalyticsName string = 'law-tracing-${suffix}'

@description('Name of the Application Insights component to create.')
param appInsightsName string = 'appi-tracing-${suffix}'

resource aiAccount 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = {
name: aiAccountName
scope: resourceGroup()
}

resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = {
name: logAnalyticsName
location: location
properties: {
sku: {
name: 'PerGB2018'
}
retentionInDays: 30
}
}

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
name: appInsightsName
location: location
kind: 'web'
properties: {
Application_Type: 'web'
WorkspaceResourceId: logAnalytics.id
publicNetworkAccessForIngestion: disablePublicIngestion ? 'Disabled' : 'Enabled'
publicNetworkAccessForQuery: 'Enabled'
}
}

// Foundry account connection (category AppInsights) so the agent exports OTel traces here.
resource connection 'Microsoft.CognitiveServices/accounts/connections@2025-04-01-preview' = {
name: '${aiAccountName}-appinsights'
parent: aiAccount
properties: {
category: 'AppInsights'
target: appInsights.id
authType: 'ApiKey'
isSharedToAll: true
credentials: {
key: appInsights.properties.ConnectionString
}
metadata: {
ApiType: 'Azure'
ResourceId: appInsights.id
}
}
}

@description('Resource ID of the Application Insights component.')
output appInsightsId string = appInsights.id

@description('Application ID of the Application Insights component (for trace queries).')
output appInsightsAppId string = appInsights.properties.AppId

@description('Resource ID of the Log Analytics workspace backing Application Insights.')
output logAnalyticsId string = logAnalytics.id
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
Azure Monitor Private Link Scope (AMPLS) Module
-----------------------------------------------
This module enables private trace ingestion to Application Insights with:
1. Azure Monitor Private Link Scope (PrivateOnly ingestion, Open query)
2. Application Insights and Log Analytics added as scoped resources
3. Azure Monitor private DNS zones linked to the VNet
4. Private Endpoint (azuremonitor) in the PE subnet with a DNS zone group
*/

@description('Azure region for the private endpoint.')
param location string

@description('Suffix for unique resource names (the template uniqueSuffix).')
param suffix string

@description('Resource ID of the Application Insights component to scope into the AMPLS.')
param appInsightsId string

@description('Resource ID of the Log Analytics workspace to scope into the AMPLS.')
param logAnalyticsId string

@description('Resource ID of the Virtual Network.')
param vnetId string

@description('Resource ID of the Private Endpoint subnet.')
param peSubnetId string

@description('Map of Azure Monitor private DNS zone name to the resource group of an existing zone. An empty string for a zone means the module creates and links it in this resource group; a non-empty resource group means bring your own existing (e.g. centralized Azure Landing Zone) zone, which is referenced instead of recreated.')
param existingDnsZones object = {
'privatelink.monitor.azure.com': ''
'privatelink.oms.opinsights.azure.com': ''
'privatelink.ods.opinsights.azure.com': ''
'privatelink.agentsvc.azure-automation.net': ''
}

@description('Subscription ID where existing Azure Monitor private DNS zones are located. Defaults to the current subscription.')
param dnsZonesSubscriptionId string = subscription().subscriptionId

// Azure Monitor private DNS zones. Blob zone omitted: the standard templates already create + link it for BYO storage.
var monitorDnsZoneNames = [
'privatelink.monitor.azure.com'
'privatelink.oms.opinsights.azure.com'
'privatelink.ods.opinsights.azure.com'
'privatelink.agentsvc.azure-automation.net'
]

// 1. Azure Monitor Private Link Scope (private ingestion, open query).
resource ampls 'Microsoft.Insights/privateLinkScopes@2021-07-01-preview' = {
name: 'ampls-tracing-${suffix}'
location: 'global'
properties: {
accessModeSettings: {
ingestionAccessMode: 'PrivateOnly'
queryAccessMode: 'Open'
}
}
}

// 2. Scope the Application Insights component and its Log Analytics workspace.
resource amplsAppInsights 'Microsoft.Insights/privateLinkScopes/scopedResources@2021-07-01-preview' = {
parent: ampls
name: 'appinsights-scoped'
properties: {
linkedResourceId: appInsightsId
}
}

resource amplsLogAnalytics 'Microsoft.Insights/privateLinkScopes/scopedResources@2021-07-01-preview' = {
parent: ampls
name: 'law-scoped'
properties: {
linkedResourceId: logAnalyticsId
}
}

// 3. The Azure Monitor private DNS zones. Zones are created and linked to the VNet only when
// not supplied via existingDnsZones; bring-your-own (centralized) zones are referenced as-is and
// are neither recreated nor relinked here, matching the ALZ centralized Private DNS Zone model.
resource monitorDnsZones 'Microsoft.Network/privateDnsZones@2020-06-01' = [for zone in monitorDnsZoneNames: if (empty(existingDnsZones[zone])) {
name: zone
location: 'global'
}]

resource monitorDnsZoneLinks 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01' = [for (zone, i) in monitorDnsZoneNames: if (empty(existingDnsZones[zone])) {
parent: monitorDnsZones[i]
name: '${replace(zone, '.', '-')}-link'
location: 'global'
properties: {
virtualNetwork: {
id: vnetId
}
registrationEnabled: false
}
}]

// Resolve each zone's resource ID: a newly created zone lives in this resource group, while a
// bring-your-own zone is referenced in its (optionally cross-subscription) resource group.
var monitorDnsZoneIds = [for zone in monitorDnsZoneNames: empty(existingDnsZones[zone])
? resourceId('Microsoft.Network/privateDnsZones', zone)
: extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', dnsZonesSubscriptionId, existingDnsZones[zone]), 'Microsoft.Network/privateDnsZones', zone)]

// 4. Private endpoint to the AMPLS (group 'azuremonitor') + DNS zone group.
resource amplsPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-05-01' = {
name: 'ampls-tracing-${suffix}-pe'
location: location
properties: {
subnet: {
id: peSubnetId
}
privateLinkServiceConnections: [
{
name: 'ampls-connection'
properties: {
privateLinkServiceId: ampls.id
groupIds: [
'azuremonitor'
]
}
}
]
}
dependsOn: [
amplsAppInsights
amplsLogAnalytics
]
}

resource amplsDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2024-05-01' = {
parent: amplsPrivateEndpoint
name: 'ampls-dns'
properties: {
privateDnsZoneConfigs: [for (zone, i) in monitorDnsZoneNames: {
name: replace(zone, '.', '-')
properties: {
privateDnsZoneId: monitorDnsZoneIds[i]
}
}]
}
dependsOn: [
monitorDnsZoneLinks
]
}

@description('Resource ID of the Azure Monitor Private Link Scope.')
output amplsId string = ampls.id
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,19 @@ Cosmos DB Account
- Disabled local auth
- Single region deployment

Azure Monitor (Application Insights & Log Analytics)
- Log Analytics Workspace: Microsoft.OperationalInsights/workspaces
- SKU: PerGB2018
- Retention: 30 days
- Application Insights: Microsoft.Insights/components
- Kind: web
- Linked to Log Analytics workspace
- Public ingestion disabled (reached privately via AMPLS)
- Azure Monitor Private Link Scope (AMPLS): microsoft.insights/privateLinkScopes
- Access mode: PrivateOnly ingestion, Open query
- Scoped resources: Application Insights + Log Analytics
- Enables hosted agents to export telemetry via private network

### Network Security Design
This implementation utilizes a BYO VNet (Bring Your Own Virtual Network) approach, also known as custom VNet support with subnet delegation. Within your existing virtual network, one delegated subnet will be created.

Expand All @@ -433,6 +446,7 @@ Private endpoints ensure secure, internal-only connectivity. Private endpoints a
- Azure AI Search
- Azure Storage
- Azure Cosmos DB
- Azure Monitor Private Link Scope (AMPLS) — enables telemetry export from hosted agents

**Private DNS Zones**
| Private Link Resource Type | Sub Resource | Private DNS Zone Name | Public DNS Zone Forwarders |
Expand All @@ -441,6 +455,7 @@ Private endpoints ensure secure, internal-only connectivity. Private endpoints a
| **Azure AI Search** | searchService| `privatelink.search.windows.net` | `search.windows.net` |
| **Azure Cosmos DB** | Sql | `privatelink.documents.azure.com` | `documents.azure.com` |
| **Azure Storage** | blob | `privatelink.blob.core.windows.net` | `blob.core.windows.net` |
| **Azure Monitor (AMPLS)** | azuremonitor | `privatelink.monitor.azure.com`<br>`privatelink.oms.opinsights.azure.com`<br>`privatelink.ods.opinsights.azure.com`<br>`privatelink.agentsvc.azure-automation.net` | `monitor.azure.com`<br>`oms.opinsights.azure.com`<br>`ods.opinsights.azure.com`<br>`agentsvc.azure-automation.net` |

### Authentication & Authorization

Expand Down Expand Up @@ -483,12 +498,14 @@ modules-network-secured/
├── ai-account-identity.bicep # Microsoft Foundry deployment and configuration (supports BYO existing account)
├── ai-project-identity.bicep # Foundry project deployment and connection configuration
├── ai-search-role-assignments.bicep # AI Search RBAC configuration
├── application-insights.bicep # Workspace-based Application Insights for agent tracing
├── azure-storage-account-role-assignments.bicep # Storage Account RBAC configuration
├── blob-storage-container-role-assignments.bicep # Blob Storage Container RBAC configuration
├── cosmos-container-role-assignments.bicep # CosmosDB container Account RBAC configuration
├── cosmosdb-account-role-assignment.bicep # CosmosDB Account RBAC configuration
├── existing-vnet.bicep # Bring your existing virtual network to template deployment
├── format-project-workspace-id.bicep # Formatting the project workspace ID
├── monitor-private-link-scope.bicep # Azure Monitor Private Link Scope (AMPLS) for private telemetry ingestion
├── network-agent-vnet.bicep # Logic for routing virtual network set-up if existing virtual network is selected
├── private-endpoint-and-dns.bicep # Creating virtual networks and DNS zones.
├── standard-dependent-resources.bicep # Deploying CosmosDB, Storage, and Search
Expand Down
Loading
Loading