diff --git a/policyAssignments/dev/pa-d-cog-service.json b/policyAssignments/dev/pa-d-cog-service.json index 18296f2..00f81d5 100644 --- a/policyAssignments/dev/pa-d-cog-service.json +++ b/policyAssignments/dev/pa-d-cog-service.json @@ -70,6 +70,31 @@ "value": [ "FW-Kimi-K3" ] + }, + "COG-010_Effect": { + "value": "Deny" + }, + "COG-010_approvedRaiPolicies": { + "value": [ + "Microsoft.DefaultV2", + "Contoso.DefaultV1" + ] + }, + "COG-011_Effect": { + "value": "Deny" + }, + "COG-011_modelNames": { + "value": [ + "gpt-5-mini", + "gpt-5-nano", + "gpt-5.2", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4", + "gpt-5.5", + "FW-Kimi-K3", + "FW-Kimi-K2.7-Code" + ] } }, "nonComplianceMessages": [ @@ -80,6 +105,10 @@ { "policyDefinitionReferenceId": "COG-007", "message": "PolicyID: COG-007 Violation in polset-cognitive-service Initiative - 'Only approved xAI models are allowed to be deployed in Cognitive Services'" + }, + { + "policyDefinitionReferenceId": "COG-011", + "message": "PolicyID: COG-011 Violation in polset-cognitive-service Initiative - 'List of Foundry model deployments must use DataZoneStandard deployment type in AI Foundry accounts.'" } ], "roleDefinitionIds": [ diff --git a/policyAssignments/prod/pa-p-cog-service.json b/policyAssignments/prod/pa-p-cog-service.json index dcf4ca8..682a8d0 100644 --- a/policyAssignments/prod/pa-p-cog-service.json +++ b/policyAssignments/prod/pa-p-cog-service.json @@ -70,6 +70,31 @@ "value": [ "FW-Kimi-K3" ] + }, + "COG-010_Effect": { + "value": "Deny" + }, + "COG-010_approvedRaiPolicies": { + "value": [ + "Microsoft.DefaultV2", + "Contoso.DefaultV1" + ] + }, + "COG-011_Effect": { + "value": "Deny" + }, + "COG-011_modelNames": { + "value": [ + "gpt-5-mini", + "gpt-5-nano", + "gpt-5.2", + "gpt-5.4-mini", + "gpt-5.4-nano", + "gpt-5.4", + "gpt-5.5", + "FW-Kimi-K3", + "FW-Kimi-K2.7-Code" + ] } }, "nonComplianceMessages": [ @@ -80,6 +105,10 @@ { "policyDefinitionReferenceId": "COG-007", "message": "PolicyID: COG-007 Violation in polset-cognitive-service Initiative - 'Only approved xAI models are allowed to be deployed in Cognitive Services'" + }, + { + "policyDefinitionReferenceId": "COG-011", + "message": "PolicyID: COG-011 Violation in polset-cognitive-service Initiative - 'List of Foundry model deployments must use DataZoneStandard deployment type in AI Foundry accounts.'" } ], "roleDefinitionIds": [ diff --git a/policyDefinitions/cognitive-service/pol-enforce-foundry-deployment-rai-policy.json b/policyDefinitions/cognitive-service/pol-enforce-foundry-deployment-rai-policy.json new file mode 100644 index 0000000..45a3cbe --- /dev/null +++ b/policyDefinitions/cognitive-service/pol-enforce-foundry-deployment-rai-policy.json @@ -0,0 +1,66 @@ +{ + "name": "pol-enforce-foundry-deployment-rai-policy", + "properties": { + "displayName": "Foundry deployments must have an approved Responsible AI policy assigned", + "description": "Ensure Foundry model deployments have an associated approved Responsible AI policy.", + "mode": "All", + "metadata": { + "version": "1.0.0", + "category": "Cognitive Services", + "preview": false, + "deprecated": false + }, + "parameters": { + "effect": { + "type": "String", + "metadata": { + "displayName": "Effect", + "description": "Enable or disable execution of the policy." + }, + "allowedValues": [ + "Audit", + "Deny", + "Disabled" + ], + "defaultValue": "Audit" + }, + "approvedRaiPolicies": { + "type": "Array", + "metadata": { + "displayName": "Approved RAI policy names", + "description": "Responsible AI policy names that satisfy the organisation content safety baseline." + }, + "defaultValue": [ + "Microsoft.DefaultV2" + ] + } + }, + "policyRule": { + "if": { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/deployments" + }, + { + "anyOf": [ + { + "field": "Microsoft.CognitiveServices/accounts/deployments/raiPolicyName", + "exists": "false" + }, + { + "not": { + "field": "Microsoft.CognitiveServices/accounts/deployments/raiPolicyName", + "in": "[parameters('approvedRaiPolicies')]" + } + } + ] + } + ] + }, + "then": { + "effect": "[parameters('effect')]" + } + } + } +} diff --git a/policyDefinitions/cognitive-service/pol-enforce-foundry-model-deployment-type.json b/policyDefinitions/cognitive-service/pol-enforce-foundry-model-deployment-type.json new file mode 100644 index 0000000..e53fa5c --- /dev/null +++ b/policyDefinitions/cognitive-service/pol-enforce-foundry-model-deployment-type.json @@ -0,0 +1,63 @@ +{ + "name": "pol-enforce-foundry-model-deployment-type", + "properties": { + "displayName": "List of Foundry Model deployments must use approved deployment type", + "mode": "All", + "description": "Enforce Foundry models to be deployed using approved deployment types.", + "metadata": { + "version": "1.0.0", + "category": "Cognitive Services" + }, + "parameters": { + "effect": { + "type": "String", + "metadata": { + "displayName": "Effect", + "description": "Enable or disable execution of the policy." + }, + "allowedValues": [ + "Audit", + "Deny", + "Disabled" + ], + "defaultValue": "Deny" + }, + "modelNames": { + "type": "Array", + "metadata": { + "displayName": "In-scope model names", + "description": "Model names this restriction applies to. Matched against model.name. Comparison is case-insensitive." + } + }, + "allowedDeploymentType": { + "type": "string", + "metadata": { + "displayName": "Approved deployment type", + "description": "Permitted value of sku.name for the in-scope models." + }, + "defaultValue": "DataZoneStandard" + } + }, + "policyRule": { + "if": { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.CognitiveServices/accounts/deployments" + }, + { + "field": "Microsoft.CognitiveServices/accounts/deployments/model.name", + "in": "[parameters('modelNames')]" + }, + { + "field": "Microsoft.CognitiveServices/accounts/deployments/sku.name", + "notEquals": "[parameters('allowedDeploymentType')]" + } + ] + }, + "then": { + "effect": "[parameters('effect')]" + } + } + } +} diff --git a/policyInitiatives/polset-cognitive-service.json b/policyInitiatives/polset-cognitive-service.json index 4fe6113..a763673 100644 --- a/policyInitiatives/polset-cognitive-service.json +++ b/policyInitiatives/polset-cognitive-service.json @@ -165,6 +165,53 @@ "displayName": "COG-009 Allowed Model Names for Fireworks format", "description": "List of Model Names that are allowed to be deployed." } + }, + "COG-010_Effect": { + "type": "String", + "metadata": { + "displayName": "COG-010 Effect: Foundry deployments must have an approved Responsible AI policy assigned", + "description": "'Audit' allows a non-compliant resource to be created, but flags it as non-compliant. 'Deny' blocks the resource creation. 'Disable' turns off the policy." + }, + "allowedValues": [ + "Audit", + "Deny", + "Disabled" + ], + "defaultValue": "Deny" + }, + "COG-010_approvedRaiPolicies": { + "type": "Array", + "metadata": { + "displayName": "COG-010 Approved RAI policy names", + "description": "Responsible AI policy names that satisfy the organisation content safety baseline." + }, + "defaultValue": [ + "Microsoft.DefaultV2" + ] + }, + "COG-011_Effect": { + "type": "String", + "metadata": { + "displayName": "COG-011 Effect: List of Foundry Model deployments must use DataZoneStandard deployment type", + "description": "'Audit' allows a non-compliant resource to be created, but flags it as non-compliant. 'Deny' blocks the resource creation. 'Disable' turns off the policy." + }, + "allowedValues": [ + "Audit", + "Deny", + "Disabled" + ], + "defaultValue": "Deny" + }, + "COG-011_modelNames": { + "type": "Array", + "metadata": { + "displayName": "COG-011 In-scope model names", + "description": "Model names this restriction applies to. Matched against model.name. Comparison is case-insensitive." + }, + "defaultValue": [ + "gpt-5-mini", + "gpt-5-nano" + ] } }, "policyDefinitionGroups": [ @@ -195,6 +242,14 @@ { "name": "ISO27001-2013_A.14.2.4", "additionalMetadataId": "/providers/Microsoft.PolicyInsights/policyMetadata/ISO27001-2013_A.14.2.4" + }, + { + "name": "ISO27001-2013_A.14.2.5", + "additionalMetadataId": "/providers/Microsoft.PolicyInsights/policyMetadata/ISO27001-2013_A.14.2.5" + }, + { + "name": "ISO27001-2013_A.18.1.1", + "additionalMetadataId": "/providers/Microsoft.PolicyInsights/policyMetadata/ISO27001-2013_A.18.1.1" } ], "policyDefinitions": [ @@ -341,6 +396,39 @@ "ISO27001-2013_A.12.5.1", "ISO27001-2013_A.14.2.4" ] + }, + { + "policyDefinitionReferenceId": "COG-010", + "policyDefinitionId": "{policyLocationResourceId}/providers/Microsoft.Authorization/policyDefinitions/pol-enforce-foundry-deployment-rai-policy", + "parameters": { + "effect": { + "value": "[parameters('COG-010_Effect')]" + }, + "approvedRaiPolicies": { + "value": "[parameters('COG-010_approvedRaiPolicies')]" + } + }, + "groupNames": [ + "ISO27001-2013_A.14.2.5" + ] + }, + { + "policyDefinitionReferenceId": "COG-011", + "policyDefinitionId": "{policyLocationResourceId}/providers/Microsoft.Authorization/policyDefinitions/pol-enforce-foundry-model-deployment-type", + "parameters": { + "effect": { + "value": "[parameters('COG-011_Effect')]" + }, + "modelNames": { + "value": "[parameters('COG-011_modelNames')]" + }, + "allowedDeploymentType": { + "value": "DataZoneStandard" + } + }, + "groupNames": [ + "ISO27001-2013_A.18.1.1" + ] } ] } diff --git a/tests/policy-integration-tests/cognitive-service/README.md b/tests/policy-integration-tests/cognitive-service/README.md index ffc98f0..aeea640 100644 --- a/tests/policy-integration-tests/cognitive-service/README.md +++ b/tests/policy-integration-tests/cognitive-service/README.md @@ -23,5 +23,7 @@ The following policies are in scope for testing: | `pa-d-cog-service` | `COG-005` | Cognitive Services Deployments allowed model formats | Deny | | `pa-d-cog-service` | `COG-006` | Cognitive Services Deployments should only use approved Models from OpenAI | Deny | | `pa-d-cog-service` | `COG-007` | Cognitive Services Deployments should only use approved Models from xAI | Deny | +| `pa-d-cog-service` | `COG-010` | Cognitive Services Deployments should use an allowed Responsible AI (RAI) policy | Deny | +| `pa-d-cog-service` | `COG-011` | List of Foundry Model deployments must use DataZoneStandard deployment type | Deny | | `pa-d-diag-settings` | `DS-013` | Configure Diagnostic Setting for Azure Cognitive Services | DeployIfNotExists | | `pa-d-pedns` | `PEDNS-016` | Private DNS Record for Azure Cognitive Services PE must exist | DeployIfNotExists | diff --git a/tests/policy-integration-tests/cognitive-service/main.bad.bicep b/tests/policy-integration-tests/cognitive-service/main.bad.bicep index 2681d5f..4d89143 100644 --- a/tests/policy-integration-tests/cognitive-service/main.bad.bicep +++ b/tests/policy-integration-tests/cognitive-service/main.bad.bicep @@ -45,6 +45,21 @@ resource gpt51 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { name: 'gpt-5.1' //this should violate the policy COG-006 since gpt-5.1 is not in the allowed list of models defined in the policy format: 'OpenAI' } + raiPolicyName: 'rai-policy-1' //this should violate the policy COG-010 since rai-policy-1 is not in the allowed list of RAI policies defined in the policy + } +} +resource gpt54 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { + name: 'gpt54' + parent: cognitiveService + sku: { + name: 'GlobalStandard' //this should violate the policy COG-011 since GlobalStandard is not allowed for this model + capacity: 150 + } + properties: { + model: { + name: 'gpt-5.4' + format: 'OpenAI' + } } } diff --git a/tests/policy-integration-tests/cognitive-service/main.good.bicep b/tests/policy-integration-tests/cognitive-service/main.good.bicep index e29314e..4f34410 100644 --- a/tests/policy-integration-tests/cognitive-service/main.good.bicep +++ b/tests/policy-integration-tests/cognitive-service/main.good.bicep @@ -39,11 +39,11 @@ resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-12-01' = { ] //user owned storage defined, this should comply with the policy COG-004 } } -resource gpt41 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { - name: 'gpt41' +resource gpt54 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { + name: 'gpt54' parent: cognitiveService sku: { - name: 'GlobalStandard' + name: 'DataZoneStandard' //this should comply with the policy COG-011 since this model must use DataZoneStandard as the deployment type capacity: 150 } properties: { @@ -51,6 +51,7 @@ resource gpt41 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { name: 'gpt-5.4' format: 'OpenAI' } + raiPolicyName: 'Microsoft.DefaultV2' //this should comply with the policy COG-010 since Microsoft.DefaultV2 is in the allowed list of RAI policies defined in the policy } } @@ -67,6 +68,7 @@ resource grok 'Microsoft.CognitiveServices/accounts/deployments@2025-12-01' = { format: 'xAI' version: '1' } + raiPolicyName: 'Microsoft.DefaultV2' //this should comply with the policy COG-010 since Contoso.DefaultV1 is in the allowed list of RAI policies defined in the policy } } diff --git a/tests/policy-integration-tests/cognitive-service/tests.ps1 b/tests/policy-integration-tests/cognitive-service/tests.ps1 index 3c98634..9aaa61f 100644 --- a/tests/policy-integration-tests/cognitive-service/tests.ps1 +++ b/tests/policy-integration-tests/cognitive-service/tests.ps1 @@ -52,6 +52,14 @@ $violatingPolicies = @( policyAssignmentId = $cogServicePolicyAssignmentId policyDefinitionReferenceId = 'COG-007' } + @{ + policyAssignmentId = $cogServicePolicyAssignmentId + policyDefinitionReferenceId = 'COG-010' + } + @{ + policyAssignmentId = $cogServicePolicyAssignmentId + policyDefinitionReferenceId = 'COG-011' + } ) #define tests $tests = @()