From 49102cef2afdd20822ff51e3c1d2c2fe0d6a5b90 Mon Sep 17 00:00:00 2001 From: Dennis Eikelenboom Date: Tue, 28 Oct 2025 22:56:39 -0700 Subject: [PATCH 1/5] deny connection variants --- .../05-custom-policy-definitions/README.md | 120 ++++++++++++++++++ .../deny-disallowed-connections.json | 57 +++++++++ .../deny-key-auth-connections.json | 46 +++++++ 3 files changed, 223 insertions(+) create mode 100644 samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md create mode 100644 samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json create mode 100644 samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-key-auth-connections.json diff --git a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md new file mode 100644 index 00000000..aa040d23 --- /dev/null +++ b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md @@ -0,0 +1,120 @@ +# Custom Azure Policy Samples for AI Foundry + +Azure Policy enables you to put guardrails on resource configurations and enable self-serve resource creation in your organization. This repository shows examples for common scenarios in Azure AI Foundry. + +## Available Policies + +### 1. Deny Disallowed Connections (`deny-disallowed-connections.json`) +This policy restricts AI Foundry project connections to only allow specific categories. By default, it only allows `CognitiveSearch` connections, but this can be customized via parameters. + +**Policy Effect**: Deny +**Scope**: Microsoft.CognitiveServices/accounts/projects/connections + +### 2. Deny Key Authentication Connections (`deny-key-auth-connections.json`) +This policy prevents the creation of connections that use key-based authentication methods. + +### 3. Audit Enabled VNet Injection (`audit-enabled-vnet-injection.json`) +This policy audits whether VNet injection is properly enabled for AI Foundry resources. + +## Deployment + +### Prerequisites +- Azure CLI or Azure PowerShell +- Appropriate permissions to create Azure Policy definitions and assignments +- For subscription-level policies: Owner or Resource Policy Contributor role at subscription level +- For management group-level policies: Owner or Resource Policy Contributor role at management group level + +### Deploy using Azure CLI + +1. **Login to Azure** + ```bash + az login + az account set --subscription "" + ``` + +2. **Deploy the policy definition only** + ```bash + az deployment sub create \ + --location "East US 2" \ + --template-file main.bicep \ + --parameters main.bicepparam + ``` + +3. **Deploy with policy assignment** + ```bash + az deployment sub create \ + --location "East US 2" \ + --template-file main.bicep \ + --parameters main.bicepparam \ + --parameters assignPolicy=true + ``` + +### Deploy using Azure PowerShell + +1. **Login to Azure** + ```powershell + Connect-AzAccount + Set-AzContext -SubscriptionId "" + ``` + +2. **Deploy the policy definition only** + ```powershell + New-AzSubscriptionDeployment ` + -Location "East US 2" ` + -TemplateFile "main.bicep" ` + -TemplateParameterFile "main.bicepparam" + ``` + +3. **Deploy with policy assignment** + ```powershell + New-AzSubscriptionDeployment ` + -Location "East US 2" ` + -TemplateFile "main.bicep" ` + -TemplateParameterFile "main.bicepparam" ` + -assignPolicy $true + ``` + +### Customization + +You can customize the deployment by modifying the parameters in `main.bicepparam`: + +- **`policyName`**: Name for the policy definition +- **`allowedCategories`**: Array of allowed connection categories (default: `['CognitiveSearch']`) +- **`assignPolicy`**: Set to `true` to automatically assign the policy to the subscription +- **`assignmentName`**: Name for the policy assignment (if enabled) +- **`assignmentDisplayName`**: Display name for the policy assignment + +### Alternative: Deploy using JSON policy definitions directly + +If you prefer to use the JSON policy definitions directly without Bicep: + +```bash +# Create policy definition +az policy definition create \ + --name "deny-disallowed-connections" \ + --display-name "Foundry Developer Platform Connections Can only be AIService" \ + --description "Foundry Developer Platform Connections Can only be AIService" \ + --rules "deny-disallowed-connections.json" \ + --mode "All" + +# Assign the policy (optional) +az policy assignment create \ + --name "deny-disallowed-connections-assignment" \ + --display-name "Assignment: Foundry Developer Platform Connections Can only be AIService" \ + --policy "deny-disallowed-connections" \ + --params '{"allowedCategories":{"value":["CognitiveSearch"]}}' +``` + +## Policy Testing + +After deployment, you can test the policy by attempting to create a connection with a disallowed category: + +1. Navigate to your AI Foundry project in the Azure portal +2. Try to create a new connection with a category not in the allowed list +3. The operation should be denied with a policy violation message + +## Monitoring and Compliance + +- Use Azure Policy compliance dashboard to monitor policy compliance +- Set up alerts for policy violations +- Review policy assignment effects regularly to ensure they meet your governance requirements diff --git a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json new file mode 100644 index 00000000..2bdaaf33 --- /dev/null +++ b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json @@ -0,0 +1,57 @@ +{ + "properties": { + "displayName": "Only selected Foundry connection categories are allowed", + "policyType": "Custom", + "mode": "All", + "description": "Only selected Foundry connection categories are allowed", + "version": "1.0.0", + "parameters": { + "allowedCategories": { + "type": "Array", + "metadata": { + "description": "Categories allowed for Microsoft.CognitiveServices/accounts/connections and Microsoft.CognitiveServices/accounts/projects/connections", + "displayName": "Allowed connection categories" + }, + "defaultValue": [ + "CognitiveSearch" + ] + } + }, + "policyRule": { + "if": { + "anyOf": [ + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/connections" + }, + { + "field": "Microsoft.CognitiveServices/accounts/connections/category", + "notIn": "[parameters('allowedCategories')]" + } + ] + }, + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/projects/connections" + }, + { + "field": "Microsoft.CognitiveServices/accounts/projects/connections/category", + "notIn": "[parameters('allowedCategories')]" + } + ] + } + ] + }, + "then": { + "effect": "deny" + } + }, + "versions": [ + "1.0.0" + ] + } +} \ No newline at end of file diff --git a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-key-auth-connections.json b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-key-auth-connections.json new file mode 100644 index 00000000..0f496fd9 --- /dev/null +++ b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-key-auth-connections.json @@ -0,0 +1,46 @@ +{ + "properties": { + "displayName": "Deny AI Foundry connections using API key-based authentication", + "policyType": "Custom", + "mode": "All", + "description": "This policy denies the creation of connections that use API key authentication for enhanced security", + "version": "1.0.0", + "parameters": {}, + "policyRule": { + "if": { + "anyOf": [ + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/projects/connections" + }, + { + "field": "Microsoft.CognitiveServices/accounts/projects/connections/authType", + "equals": "ApiKey" + } + ] + }, + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/connections" + }, + { + "field": "Microsoft.CognitiveServices/accounts/connections/authType", + "equals": "ApiKey" + } + ] + } + ] + }, + "then": { + "effect": "deny" + } + }, + "versions": [ + "1.0.0" + ] + } +} \ No newline at end of file From 5379c704c1216f98cceb92953978ca0cdec0e9fd Mon Sep 17 00:00:00 2001 From: Dennis Eikelenboom Date: Wed, 29 Oct 2025 16:52:52 -0700 Subject: [PATCH 2/5] include custom policy samples --- .../deny-disallowed-connections.json | 2 +- .../deny-disallowed-mcp-tools.json | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-mcp-tools.json diff --git a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json index 2bdaaf33..3ef8afb2 100644 --- a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json +++ b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-connections.json @@ -13,7 +13,7 @@ "displayName": "Allowed connection categories" }, "defaultValue": [ - "CognitiveSearch" + "BingLLMSearch" ] } }, diff --git a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-mcp-tools.json b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-mcp-tools.json new file mode 100644 index 00000000..d0f38b5f --- /dev/null +++ b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-disallowed-mcp-tools.json @@ -0,0 +1,65 @@ +{ + "properties": { + "displayName": "Only allow Foundry MCP connections from select sources", + "policyType": "Custom", + "mode": "All", + "description": "Only selected Foundry MCP connection sources are allowed", + "version": "1.0.0", + "parameters": { + "allowedSources": { + "type": "Array", + "metadata": { + "description": "Only select target addresses are allowed for MCP connections.", + "displayName": "Allowed connection targets" + }, + "defaultValue": [ + "https://api.githubcopilot.com/mcp" + ] + } + }, + "policyRule": { + "if": { + "anyOf": [ + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/connections" + }, + { + "field": "Microsoft.CognitiveServices/accounts/connections/category", + "equals": "RemoteTool" + }, + { + "field": "Microsoft.CognitiveServices/accounts/connections/target", + "notIn": "[parameters('allowedSources')]" + } + ] + }, + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/projects/connections" + }, + { + "field": "Microsoft.CognitiveServices/accounts/connections/category", + "equals": "RemoteTool" + }, + { + "field": "Microsoft.CognitiveServices/accounts/projects/connections/target", + "notIn": "[parameters('allowedSources')]" + } + ] + } + ] + }, + "then": { + "effect": "deny" + } + }, + "versions": [ + "1.0.0" + ] + } +} \ No newline at end of file From 03804ab80ea1a5253d5275b4a69584d74e6659c9 Mon Sep 17 00:00:00 2001 From: Dennis Eikelenboom Date: Wed, 29 Oct 2025 18:10:25 -0700 Subject: [PATCH 3/5] add sample --- .../05-custom-policy-definitions/README.md | 14 --------- .../deny-non-foundry-resource-kinds.json | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-non-foundry-resource-kinds.json diff --git a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md index aa040d23..364a8fc7 100644 --- a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md +++ b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/README.md @@ -2,20 +2,6 @@ Azure Policy enables you to put guardrails on resource configurations and enable self-serve resource creation in your organization. This repository shows examples for common scenarios in Azure AI Foundry. -## Available Policies - -### 1. Deny Disallowed Connections (`deny-disallowed-connections.json`) -This policy restricts AI Foundry project connections to only allow specific categories. By default, it only allows `CognitiveSearch` connections, but this can be customized via parameters. - -**Policy Effect**: Deny -**Scope**: Microsoft.CognitiveServices/accounts/projects/connections - -### 2. Deny Key Authentication Connections (`deny-key-auth-connections.json`) -This policy prevents the creation of connections that use key-based authentication methods. - -### 3. Audit Enabled VNet Injection (`audit-enabled-vnet-injection.json`) -This policy audits whether VNet injection is properly enabled for AI Foundry resources. - ## Deployment ### Prerequisites diff --git a/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-non-foundry-resource-kinds.json b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-non-foundry-resource-kinds.json new file mode 100644 index 00000000..0a231d9e --- /dev/null +++ b/samples/microsoft/infrastructure-setup/05-custom-policy-definitions/deny-non-foundry-resource-kinds.json @@ -0,0 +1,30 @@ +{ + "properties": { + "displayName": "Deny account kinds that do not support the full AI Foundry capabilities.", + "policyType": "Custom", + "mode": "All", + "description": "This policy denies the creation of account kinds that do not support the full AI Foundry capabilities.", + "version": "1.0.0", + "parameters": {}, + "policyRule": { + "if": { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts" + }, + { + "field": "kind", + "notEquals": "AIServices" + } + ] + }, + "then": { + "effect": "deny" + } + }, + "versions": [ + "1.0.0" + ] + } +} \ No newline at end of file From 9bb1e2623d139b7ac227af2ff073a5516a8eda71 Mon Sep 17 00:00:00 2001 From: Dennis Eikelenboom Date: Wed, 5 Nov 2025 07:27:28 -0800 Subject: [PATCH 4/5] fix sample --- .../00-basic-azurerm/code/providers.tf | 1 + .../00-basic-azurerm/code/variables.tf | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/providers.tf b/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/providers.tf index 589a2a75..d8c5de46 100644 --- a/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/providers.tf +++ b/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/providers.tf @@ -2,4 +2,5 @@ provider "azurerm" { features {} storage_use_azuread = true + subscription_id = var.subscription_id } diff --git a/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/variables.tf b/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/variables.tf index 80a80a89..76351d2b 100644 --- a/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/variables.tf +++ b/samples/microsoft/infrastructure-setup-terraform/00-basic-azurerm/code/variables.tf @@ -2,3 +2,7 @@ variable "location" { description = "The name of the location to provision the resources to" type = string } + +variable "subscription_id" { + type = string +} \ No newline at end of file From 15c4d6e83f88cf0d5885abe9a181bf938c50edad Mon Sep 17 00:00:00 2001 From: Dennis Eikelenboom Date: Wed, 5 Nov 2025 07:34:17 -0800 Subject: [PATCH 5/5] fix missing var --- .../infrastructure-setup-terraform/00-basic/code/providers.tf | 1 + .../infrastructure-setup-terraform/00-basic/code/variables.tf | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/samples/microsoft/infrastructure-setup-terraform/00-basic/code/providers.tf b/samples/microsoft/infrastructure-setup-terraform/00-basic/code/providers.tf index 8b31bb74..f8b31524 100644 --- a/samples/microsoft/infrastructure-setup-terraform/00-basic/code/providers.tf +++ b/samples/microsoft/infrastructure-setup-terraform/00-basic/code/providers.tf @@ -1,3 +1,4 @@ # Setup providers provider "azapi" { + subscription_id = var.subscription_id } \ No newline at end of file diff --git a/samples/microsoft/infrastructure-setup-terraform/00-basic/code/variables.tf b/samples/microsoft/infrastructure-setup-terraform/00-basic/code/variables.tf index 80a80a89..76351d2b 100644 --- a/samples/microsoft/infrastructure-setup-terraform/00-basic/code/variables.tf +++ b/samples/microsoft/infrastructure-setup-terraform/00-basic/code/variables.tf @@ -2,3 +2,7 @@ variable "location" { description = "The name of the location to provision the resources to" type = string } + +variable "subscription_id" { + type = string +} \ No newline at end of file