test(azure_policy): add end-to-end policy test cases (#699)

50 end-to-end test cases derived from real Azure built-in policies. Each
file contains a complete policy definition, sample resources, and expected
evaluation results. Coverage spans storage, networking, compute, security,
monitoring, database, identity, governance, and update management scenarios.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anand Krishnamoorthi
2026-04-27 18:04:50 -05:00
committed by GitHub
parent b989888dab
commit afdb894d85
50 changed files with 17757 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Monitoring/ActivityLog_CaptureAllRegions
# Features: AuditIfNotExists with inline existenceCondition using
# implicit allOf over [*] wildcard fields + not-wrapping.
#
# NOTE: Without an alias catalog, fully-qualified field paths like
# "Microsoft.Insights/logProfiles/locations[*]" resolve as raw object
# keys. The test response structure mirrors this resolution.
policy_definition: |
{
"properties": {
"displayName": "Azure Monitor should collect activity logs from all regions",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "AuditIfNotExists",
"allowedValues": ["AuditIfNotExists", "Disabled"]
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Resources/subscriptions"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Insights/logProfiles",
"existenceCondition": {
"allOf": [
{
"not": {
"field": "Microsoft.Insights/logProfiles/locations[*]",
"notEquals": "eastus"
}
},
{
"not": {
"field": "Microsoft.Insights/logProfiles/locations[*]",
"notEquals": "westus"
}
},
{
"not": {
"field": "Microsoft.Insights/logProfiles/locations[*]",
"notEquals": "global"
}
}
]
}
}
}
}
}
}
cases:
# Related resource not found → non-compliant
- note: non_compliant_resource_not_found
resource:
type: "Microsoft.Resources/subscriptions"
name: "sub-a"
properties: {}
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Insights/logProfiles"
response: null
want_effect: "AuditIfNotExists"
# Related resource found with all required regions → compliant
- note: compliant_all_regions_present
resource:
type: "Microsoft.Resources/subscriptions"
name: "sub-b"
properties: {}
host_await:
- response:
Microsoft:
"Insights/logProfiles/locations":
- eastus
- westus
- global
want_undefined: true
# Related resource found but missing a region → non-compliant
- note: non_compliant_missing_region
resource:
type: "Microsoft.Resources/subscriptions"
name: "sub-c"
properties: {}
host_await:
- response:
Microsoft:
"Insights/logProfiles/locations":
- eastus
- westus
want_effect: "AuditIfNotExists"

View File

@@ -0,0 +1,227 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Resilience/ContainerService_managedclusters_ZoneRedundant_Audit
# Real Azure Policy: "Azure Kubernetes Service Managed Clusters should be
# Zone Redundant"
# Features: allOf, anyOf, field (type + alias), equals, field count with where,
# nested field count ([*] inside [*]), less, greater, parameters() with
# defaultValue
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Preview]: Azure Kubernetes Service Managed Clusters should be Zone Redundant",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect"
},
"allowedValues": ["Audit", "Deny", "Disabled"],
"defaultValue": "Audit"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.ContainerService/managedclusters"
},
{
"anyOf": [
{
"count": {
"field": "Microsoft.ContainerService/managedClusters/agentPoolProfiles[*]",
"where": {
"count": {
"field": "Microsoft.ContainerService/managedClusters/agentPoolProfiles[*].availabilityZones[*]"
},
"less": 3
}
},
"greater": 0
},
{
"count": {
"field": "Microsoft.ContainerService/managedClusters/agentPoolProfiles[*]",
"where": {
"field": "Microsoft.ContainerService/managedClusters/agentPoolProfiles[*].count",
"less": 3
}
},
"greater": 0
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# No effect — all pools have 3 AZs and count >= 3
# =========================================================================
- note: pass_fully_zone_redundant
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "myAKS"
location: "eastus"
properties:
agentPoolProfiles:
- name: "system"
count: 3
availabilityZones: ["1", "2", "3"]
- name: "user"
count: 5
availabilityZones: ["1", "2", "3"]
want_undefined: true
# =========================================================================
# Audit — one pool has fewer than 3 AZs
# =========================================================================
- note: audit_pool_missing_az
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "myAKS"
location: "eastus"
properties:
agentPoolProfiles:
- name: "system"
count: 3
availabilityZones: ["1", "2", "3"]
- name: "user"
count: 3
availabilityZones: ["1", "2"]
want_effect: "Audit"
# =========================================================================
# Audit — one pool has no AZs at all
# =========================================================================
- note: audit_pool_no_azs
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "myAKS"
location: "westus"
properties:
agentPoolProfiles:
- name: "system"
count: 3
availabilityZones: ["1", "2", "3"]
- name: "badpool"
count: 3
availabilityZones: []
want_effect: "Audit"
# =========================================================================
# Audit — pool count < 3 (even with 3 AZs)
# =========================================================================
- note: audit_pool_low_count
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "myAKS"
location: "eastus"
properties:
agentPoolProfiles:
- name: "system"
count: 2
availabilityZones: ["1", "2", "3"]
want_effect: "Audit"
# =========================================================================
# Audit — both: pool has 2 AZs and count = 1
# =========================================================================
- note: audit_both_violations
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "tinyAKS"
location: "eastus"
properties:
agentPoolProfiles:
- name: "system"
count: 1
availabilityZones: ["1"]
want_effect: "Audit"
# =========================================================================
# No effect — wrong resource type
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "myVM"
location: "eastus"
properties: {}
want_undefined: true
# =========================================================================
# Audit — single pool, exactly 3 AZs but count = 2
# =========================================================================
- note: audit_three_azs_low_count
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "myAKS"
location: "eastus"
properties:
agentPoolProfiles:
- name: "system"
count: 2
availabilityZones: ["1", "2", "3"]
want_effect: "Audit"
# =========================================================================
# Deny — explicit effect parameter override
# =========================================================================
- note: deny_with_explicit_effect
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "myAKS"
location: "eastus"
properties:
agentPoolProfiles:
- name: "system"
count: 1
availabilityZones: []
parameters:
effect: "Deny"
want_effect: "Deny"
# =========================================================================
# No effect — three pools, all fully zone-redundant
# =========================================================================
- note: pass_three_pools_all_good
resource:
type: "Microsoft.ContainerService/managedclusters"
name: "bigAKS"
location: "eastus"
properties:
agentPoolProfiles:
- name: "system"
count: 3
availabilityZones: ["1", "2", "3"]
- name: "user1"
count: 6
availabilityZones: ["1", "2", "3"]
- name: "user2"
count: 9
availabilityZones: ["1", "2", "3"]
want_undefined: true

View File

@@ -0,0 +1,192 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: VirtualEnclaves/ApprovedVirtualNetworkSubnets_Deny
# Real Azure Policy: "Network interfaces should be connected to an approved subnet
# of the approved virtual network"
# Source: regolator/policyDefinitions/VirtualEnclaves/ApprovedVirtualNetworkSubnets_Deny.json
#
# Features exercised:
# - Value count with named iterator: count { value: params, name: "subnetName" }
# - current('subnetName') to reference the iterator value
# - concat() to build dynamic resource IDs
# - Boolean parameter branching (allowAllSubnets true vs false)
# - not { field like concat(...) } double-negation on wildcard array
# - Two distinct allOf branches inside anyOf based on parameter value
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Network interfaces should be connected to an approved subnet of the approved virtual network",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"defaultValue": "Deny",
"allowedValues": ["Audit", "Deny", "Disabled"]
},
"virtualNetworkId": {
"type": "String",
"metadata": {
"displayName": "Virtual network Id"
}
},
"allowedSubnetList": {
"type": "Array",
"defaultValue": []
},
"allowAllSubnets": {
"type": "Boolean",
"defaultValue": true
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkInterfaces"
},
{
"anyOf": [
{
"allOf": [
{
"value": "[parameters('allowAllSubnets')]",
"equals": true
},
{
"not": {
"field": "Microsoft.Network/networkInterfaces/ipconfigurations[*].subnet.id",
"like": "[concat(parameters('virtualNetworkId'),'/*')]"
}
}
]
},
{
"allOf": [
{
"value": "[parameters('allowAllSubnets')]",
"equals": false
},
{
"count": {
"value": "[parameters('allowedSubnetList')]",
"name": "subnetName",
"where": {
"field": "Microsoft.Network/networkInterfaces/ipconfigurations[*].subnet.id",
"equals": "[concat(parameters('virtualNetworkId'),'/subnets/',current('subnetName'))]"
}
},
"equals": 0
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Branch 1: allowAllSubnets = true — any subnet in the VNet is OK
# =========================================================================
- note: pass_allow_all_subnets_correct_vnet
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-good-vnet"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/default"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
allowAllSubnets: true
want_undefined: true
- note: deny_allow_all_subnets_wrong_vnet
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-wrong-vnet"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet2/subnets/default"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
allowAllSubnets: true
want_effect: "Deny"
# =========================================================================
# Branch 2: allowAllSubnets = false — value count with subnet list
# =========================================================================
- note: pass_specific_subnet_allowed
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-allowed-subnet"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/frontend"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
allowAllSubnets: false
allowedSubnetList: ["frontend", "backend"]
want_undefined: true
- note: deny_subnet_not_in_allowed_list
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-bad-subnet"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/management"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
allowAllSubnets: false
allowedSubnetList: ["frontend", "backend"]
want_effect: "Deny"
- note: deny_empty_subnet_list
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-no-list"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/default"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
allowAllSubnets: false
allowedSubnetList: []
want_effect: "Deny"
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "not-a-nic"
properties: {}
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
want_undefined: true

View File

@@ -0,0 +1,134 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Network/ApprovedVirtualNetwork_Audit
# Real Azure Policy: "Virtual machines should be connected to an approved virtual network"
# Source: regolator/policyDefinitions/Network/ApprovedVirtualNetwork_Audit.json
#
# Features exercised:
# - not { field like concat(...) } — double negation on wildcard array
# - concat() to build VNet prefix pattern
# - Wildcard array alias: ipconfigurations[*].subnet.id
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Virtual machines should be connected to an approved virtual network",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Deny", "Disabled"]
},
"virtualNetworkId": {
"type": "string",
"metadata": {
"displayName": "Virtual network Id"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkInterfaces"
},
{
"not": {
"field": "Microsoft.Network/networkInterfaces/ipconfigurations[*].subnet.id",
"like": "[concat(parameters('virtualNetworkId'),'/*')]"
}
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# NIC in approved VNet → pass
# =========================================================================
- note: pass_nic_in_approved_vnet
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-good"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet/subnets/default"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet"
want_undefined: true
- note: pass_multiple_ips_all_in_approved_vnet
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-multi-good"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet/subnets/subnet1"
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet/subnets/subnet2"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet"
want_undefined: true
# =========================================================================
# NIC in wrong VNet → audit
# =========================================================================
- note: audit_nic_in_wrong_vnet
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-bad"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/other-vnet/subnets/default"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet"
want_effect: "Audit"
- note: audit_one_ip_in_wrong_vnet
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-mixed-vnet"
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet/subnets/subnet1"
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/other-vnet/subnets/subnet1"
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet"
want_effect: "Audit"
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "not-nic"
properties: {}
parameters:
virtualNetworkId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/approved-vnet"
want_undefined: true

View File

@@ -0,0 +1,250 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Network/ASC_All_Internet_traffic_should_be_routed_via_Azure_Firewall
# Real Azure Policy: "[Preview]: All Internet traffic should be routed via
# your deployed Azure Firewall"
# Source: regolator/policyDefinitions/Network/ASC_All_Internet_traffic_should_be_routed_via_Azure_Firewall.json
#
# Features exercised:
# - Nested array count: subnets[*] containing ipConfigurations[*]
# - Count in existenceCondition (503-policy gap)
# - Double negation: not { anyOf [name excludes] }
# - subscription().subscriptionId, first(), split(), field('fullName')
# - empty() on doubly-nested array field
# - AuditIfNotExists with existence count check
# - like operator with wildcard pattern in existenceCondition
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Preview]: All Internet traffic should be routed via your deployed Azure Firewall",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "AuditIfNotExists",
"allowedValues": ["AuditIfNotExists", "Disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/virtualNetworks"
},
{
"count": {
"field": "Microsoft.Network/virtualNetworks/subnets[*]",
"where": {
"allOf": [
{
"count": {
"field": "Microsoft.Network/virtualNetworks/subnets[*].ipConfigurations[*]",
"where": {
"value": "[empty(field('Microsoft.Network/virtualNetworks/subnets[*].ipConfigurations[*].id'))]",
"equals": false
}
},
"greaterOrEquals": 2
},
{
"field": "Microsoft.Network/virtualNetworks/subnets[*].routeTable",
"exists": false
},
{
"not": {
"anyOf": [
{
"field": "Microsoft.Network/virtualNetworks/subnets[*].name",
"equals": "AzureBastionSubnet"
},
{
"field": "Microsoft.Network/virtualNetworks/subnets[*].name",
"equals": "GatewaySubnet"
}
]
}
}
]
}
},
"greater": 0
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Network/azureFirewalls",
"existenceCondition": {
"count": {
"field": "Microsoft.Network/azureFirewalls/ipConfigurations[*]",
"where": {
"field": "Microsoft.Network/azureFirewalls/ipConfigurations[*].subnet.id",
"like": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/*/providers/Microsoft.Network/virtualNetworks/', first(split(field('fullName'), '/')), '/subnets/AzureFirewallSubnet')]"
}
},
"equals": 1
}
}
}
}
}
}
cases:
# =========================================================================
# AINE — VNet has a qualifying subnet (2+ ipConfigs, no routeTable, not
# excluded name) and no firewall found
# =========================================================================
- note: aine_qualifying_subnet_no_firewall
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-no-fw"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet-no-fw"
properties:
subnets:
- name: "WorkloadSubnet"
properties:
ipConfigurations:
- id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/networkInterfaces/nic1/ipConfigurations/ipconfig1"
- id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/networkInterfaces/nic2/ipConfigurations/ipconfig1"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Network/azureFirewalls"
response: null
want_effect: "AuditIfNotExists"
# =========================================================================
# Pass — VNet has subnet but only 1 ipConfiguration (threshold is >=2)
# =========================================================================
- note: pass_subnet_only_one_ip_config
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-single-ip"
properties:
subnets:
- name: "AppSubnet"
properties:
ipConfigurations:
- id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/networkInterfaces/nic1/ipConfigurations/ipconfig1"
want_undefined: true
# =========================================================================
# Pass — all qualifying subnets have routeTable set
# =========================================================================
- note: pass_all_subnets_have_route_table
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-routed"
properties:
subnets:
- name: "WorkloadSubnet"
properties:
routeTable:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/routeTables/rt1"
ipConfigurations:
- id: "/subscriptions/sub1/resourceGroups/rg1/providers/nic1/ipconfig1"
- id: "/subscriptions/sub1/resourceGroups/rg1/providers/nic2/ipconfig1"
- id: "/subscriptions/sub1/resourceGroups/rg1/providers/nic3/ipconfig1"
want_undefined: true
# =========================================================================
# Pass — only excluded subnets (AzureBastionSubnet, GatewaySubnet)
# =========================================================================
- note: pass_excluded_subnets_only
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-bastion-gw"
properties:
subnets:
- name: "AzureBastionSubnet"
properties:
ipConfigurations:
- id: "/subscriptions/sub1/rg1/nic1/ip1"
- id: "/subscriptions/sub1/rg1/nic2/ip1"
- id: "/subscriptions/sub1/rg1/nic3/ip1"
- name: "GatewaySubnet"
properties:
ipConfigurations:
- id: "/subscriptions/sub1/rg1/nic4/ip1"
- id: "/subscriptions/sub1/rg1/nic5/ip1"
want_undefined: true
# =========================================================================
# AINE — qualifying subnet exists + firewall found but no matching
# ipConfiguration for this VNet
# =========================================================================
- note: aine_firewall_no_matching_subnet
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-no-match"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet-no-match"
properties:
subnets:
- name: "AppSubnet"
properties:
ipConfigurations:
- id: "/subscriptions/sub1/rg1/nic1/ip1"
- id: "/subscriptions/sub1/rg1/nic2/ip1"
host_await:
- response:
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/other-vnet/subnets/AzureFirewallSubnet"
want_effect: "AuditIfNotExists"
# =========================================================================
# Pass — qualifying subnet exists + firewall with matching VNet
# =========================================================================
- note: pass_firewall_matches_vnet
context:
resourceGroup:
name: "rg1"
location: "eastus"
subscription:
subscriptionId: "sub1"
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-protected"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet-protected"
properties:
subnets:
- name: "WorkloadSubnet"
properties:
ipConfigurations:
- id: "/subscriptions/sub1/rg1/nic1/ip1"
- id: "/subscriptions/sub1/rg1/nic2/ip1"
host_await:
- response:
properties:
ipConfigurations:
- properties:
subnet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet-protected/subnets/AzureFirewallSubnet"
want_undefined: true
# =========================================================================
# Wrong type → skip
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Network/networkSecurityGroups"
name: "nsg1"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,785 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Automanage/Deployv2
# Real Azure Policy: "Configure virtual machines to be onboarded to Azure Automanage"
# Source: regolator/policyDefinitions/Automanage/Deployv2.json
#
# Features exercised:
# - 106 condition nodes (broad, depth 4) — wide register pressure test
# - Dynamic tag field: [concat('tags[', parameters('inclusionTagName'), ']')]
# - DeployIfNotExists with conditional deployment (VM vs Arc)
# - Large hardcoded location list
# - Extensive image publisher/offer/SKU matching
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"policyType": "BuiltIn",
"mode": "Indexed",
"displayName": "Configure virtual machines to be onboarded to Azure Automanage",
"description": "Azure Automanage enrolls, configures, and monitors virtual machines with best practice as defined in the Microsoft Cloud Adoption Framework for Azure. Use this policy to apply Automanage to your selected scope.",
"version": "2.4.0",
"parameters": {
"configurationProfileAssignment": {
"type": "String",
"metadata": {
"displayName": "Configuration profile",
"description": "The management services provided are based on whether the machine is intended to be used in a dev/test environment or production."
},
"allowedValues": [
"/providers/Microsoft.Automanage/bestPractices/azurebestpracticesproduction",
"/providers/Microsoft.Automanage/bestPractices/azurebestpracticesdevtest"
],
"defaultValue": "/providers/Microsoft.Automanage/bestPractices/azurebestpracticesproduction"
},
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of this policy"
},
"allowedValues": [
"AuditIfNotExists",
"DeployIfNotExists",
"Disabled"
],
"defaultValue": "DeployIfNotExists"
},
"inclusionTagName": {
"type": "String",
"metadata": {
"displayName": "Inclusion Tag Name",
"description": "Name of the tag to use for including VMs in the scope of this policy. This should be used along with the Inclusion Tag Value parameter."
},
"defaultValue": ""
},
"inclusionTagValues": {
"type": "Array",
"metadata": {
"displayName": "Inclusion Tag Values",
"description": "Value of the tag to use for including VMs in the scope of this policy (in case of multiple values, use a comma-separated list). This should be used along with the Inclusion Tag Name parameter."
},
"defaultValue": []
}
},
"policyRule": {
"if": {
"allOf": [
{
"anyOf": [
{
"field": "[concat('tags[', parameters('inclusionTagName'), ']')]",
"in": "[parameters('inclusionTagValues')]"
},
{
"value": "[empty(parameters('inclusionTagValues'))]",
"equals": "true"
},
{
"value": "[empty(parameters('inclusionTagName'))]",
"equals": "true"
}
]
},
{
"field": "location",
"in": [
"eastus",
"eastus2",
"westus",
"westus2",
"centralus",
"southcentralus",
"westcentralus",
"northeurope",
"westeurope",
"canadacentral",
"japaneast",
"uksouth",
"australiaeast",
"australiasoutheast",
"southeastasia"
]
},
{
"field": "type",
"in": [
"Microsoft.Compute/virtualMachines",
"Microsoft.HybridCompute/machines"
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"in": [
"esri",
"incredibuild",
"MicrosoftDynamicsAX",
"MicrosoftSharepoint",
"MicrosoftVisualStudio",
"MicrosoftWindowsDesktop",
"MicrosoftWindowsServerHPCPack"
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftWindowsServer"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "2008*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftSQLServer"
},
{
"field": "Microsoft.Compute/imageOffer",
"notLike": "SQL2008*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-dsvm"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "dsvm-windows"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-ads"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"standard-data-science-vm",
"windows-data-science-vm"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "batch"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "rendering-windows2016"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "center-for-internet-security-inc"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "cis-windows-server-201*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "pivotal"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "bosh-windows-server*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "cloud-infrastructure-services"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "ad*"
}
]
},
{
"allOf": [
{
"anyOf": [
{
"field": "Microsoft.Compute/virtualMachines/osProfile.windowsConfiguration",
"exists": "true"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType",
"like": "Windows*"
}
]
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.id",
"exists": "true"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.sku",
"exists": "false"
}
]
},
{
"field": "Microsoft.Compute/imagePublisher",
"in": [
"microsoft-aks",
"qubole-inc",
"datastax",
"couchbase",
"scalegrid",
"checkpoint",
"paloaltonetworks",
"debian"
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "OpenLogic"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "CentOS*"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "OpenLogic"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "CentOS*"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "8*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "RedHat"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"RHEL",
"RHEL-HA",
"RHEL-SAP",
"RHEL-SAP-APPS",
"RHEL-SAP-HA",
"RHEL-SAP-HANA",
"rhel-raw"
]
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "RedHat"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"RHEL",
"RHEL-HA",
"RHEL-SAP",
"RHEL-SAP-APPS",
"RHEL-SAP-HA",
"RHEL-SAP-HANA",
"rhel-raw"
]
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "8*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "RedHat"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"osa",
"rhel-byos"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "center-for-internet-security-inc"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"cis-centos-7-l1",
"cis-centos-7-v2-1-1-l1",
"cis-nginx-centos-7-v1-1-0-l1",
"cis-oracle-linux-7-v2-0-0-l1",
"cis-postgresql-11-centos-linux-7-level-1",
"cis-rhel-7-l2",
"cis-rhel-7-v2-2-0-l1",
"cis-suse-linux-12-v2-0-0-l1",
"cis-suse15-l1",
"cis-ubuntu-linux-1604-v1-0-0-l1",
"cis-ubuntu-linux-1804-l1",
"cis-ubuntu-linux-2004-l1"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "credativ"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Suse"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "SLES*"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "11*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Canonical"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "UbuntuServer"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "12*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-dsvm"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"linux-data-science-vm-ubuntu",
"azureml"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "cloudera"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "cloudera-centos-os"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "cloudera"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "cloudera-altus-centos-os"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-ads"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "linux*"
}
]
},
{
"allOf": [
{
"anyOf": [
{
"field": "Microsoft.Compute/virtualMachines/osProfile.linuxConfiguration",
"exists": "true"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType",
"like": "Linux*"
}
]
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.id",
"exists": "true"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.sku",
"exists": "false"
}
]
},
{
"allOf": [
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "CentOS*"
},
{
"field": "Microsoft.HybridCompute/machines/osSku",
"notLike": "Linux 6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "Windows Server*"
},
{
"field": "Microsoft.HybridCompute/machines/osSku",
"notLike": "2008*"
}
]
},
{
"anyOf": [
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "Red Hat Enterprise Linux 8.*"
},
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "Red Hat Enterprise Linux 7.*"
}
]
},
{
"anyOf": [
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "Ubuntu 18.04*"
},
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "Ubuntu 16.04*"
},
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "Ubuntu 20.04*"
}
]
},
{
"anyOf": [
{
"field": "Microsoft.HybridCompute/machines/osSku",
"in": [
"SUSE Linux Enterprise Server 12 SP3",
"SUSE Linux Enterprise Server 12 SP4",
"SUSE Linux Enterprise Server 12 SP5"
]
},
{
"field": "Microsoft.HybridCompute/machines/osSku",
"like": "SUSE Linux Enterprise Server 15*"
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"type": "Microsoft.Automanage/configurationProfileAssignments",
"name": "default",
"existenceCondition": {
"allOf": [
{
"field": "Microsoft.Automanage/configurationProfileAssignments/configurationProfile",
"equals": "[parameters('configurationProfileAssignment')]"
}
]
},
"deployment": {
"properties": {
"mode": "incremental",
"parameters": {
"machineName": {
"value": "[field('Name')]"
},
"resourceType": {
"value": "[field('Type')]"
},
"configurationProfileAssignment": {
"value": "[parameters('configurationProfileAssignment')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"machineName": {
"type": "String"
},
"resourceType": {
"type": "String"
},
"configurationProfileAssignment": {
"type": "string"
}
},
"resources": [
{
"condition": "[equals(toLower(parameters('resourceType')), 'microsoft.compute/virtualmachines')]",
"type": "Microsoft.Compute/virtualMachines/providers/configurationProfileAssignments",
"apiVersion": "2022-05-04",
"name": "[concat(parameters('machineName'), '/Microsoft.Automanage/', 'default')]",
"properties": {
"configurationProfile": "[parameters('configurationProfileAssignment')]"
}
},
{
"condition": "[equals(toLower(parameters('resourceType')), 'microsoft.hybridcompute/machines')]",
"type": "Microsoft.HybridCompute/machines/providers/configurationProfileAssignments",
"apiVersion": "2022-05-04",
"name": "[concat(parameters('machineName'), '/Microsoft.Automanage/', 'default')]",
"properties": {
"configurationProfile": "[parameters('configurationProfileAssignment')]"
}
}
]
}
}
}
}
}
}
}
}
cases:
# =========================================================================
# DINE — Windows VM in supported region, matching publisher
# =========================================================================
- note: dine_windows_vm_canonical
resource:
type: "Microsoft.Compute/virtualMachines"
name: "win-vm-01"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/win-vm-01"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
osDisk:
osType: "Windows"
osProfile:
windowsConfiguration: {}
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Automanage/configurationProfileAssignments"
name: "default"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Pass — VM in unsupported region
# =========================================================================
- note: pass_unsupported_region
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-brazil"
location: "brazilsoutheast"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
osDisk:
osType: "Windows"
osProfile:
windowsConfiguration: {}
want_undefined: true
# =========================================================================
# DINE — Linux VM with Canonical publisher
# =========================================================================
- note: dine_linux_vm_canonical
resource:
type: "Microsoft.Compute/virtualMachines"
name: "linux-vm-01"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/linux-vm-01"
location: "westus2"
properties:
storageProfile:
imageReference:
publisher: "Canonical"
offer: "UbuntuServer"
sku: "18.04-LTS"
osDisk:
osType: "Linux"
osProfile:
linuxConfiguration: {}
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Automanage/configurationProfileAssignments"
name: "default"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Pass — VM with tag filter that doesn't match
# =========================================================================
- note: pass_tag_filter_no_match
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-tagged"
location: "eastus"
tags:
env: "dev"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
osDisk:
osType: "Windows"
osProfile:
windowsConfiguration: {}
parameters:
inclusionTagName: "env"
inclusionTagValues:
- "prod"
want_undefined: true
# =========================================================================
# Skip — Wrong resource type
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "storageacct1"
location: "eastus"
properties: {}
want_undefined: true
# =========================================================================
# Pass — VM with unsupported publisher (not in any publisher allowlist)
# =========================================================================
- note: pass_unsupported_publisher
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-unknown-pub"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm-unknown-pub"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "unknown-vendor"
offer: "some-offer"
sku: "some-sku"
osDisk:
osType: "Linux"
osProfile:
linuxConfiguration: {}
want_undefined: true

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,572 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Compute/OSAndDataDiskCMKRequired_Deny
# Real Azure Policy: "OS and data disks should be encrypted with a customer-managed key"
# Features: anyOf, allOf nesting, field (type + alias), exists, equals,
# length(), count, not, current(), multiple resource types
# (VM, VMSS, disks, images, galleries/images/versions)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "OS and data disks should be encrypted with a customer-managed key",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Use customer-managed keys to manage the encryption at rest of the contents of your managed disks. By default, the data is encrypted at rest with platform-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/disks-cmk.",
"metadata": {
"category": "Compute",
"version": "3.0.0"
},
"version": "3.0.0",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": [
"Audit",
"Deny",
"Disabled"
],
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
}
}
},
"policyRule": {
"if": {
"anyOf": [
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.managedDisk.diskEncryptionSet.id",
"exists": "False"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"value": "[length(field('Microsoft.Compute/virtualMachines/storageProfile.dataDisks'))]",
"greater": 0
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.dataDisks[*].managedDisk.id",
"exists": "False"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.dataDisks[*].managedDisk.diskEncryptionSet.id",
"exists": "False"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachineScaleSets"
},
{
"field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.storageProfile.osDisk.managedDisk.diskEncryptionSet.id",
"exists": "False"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachineScaleSets"
},
{
"count": {
"field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.storageProfile.dataDisks[*]"
},
"greater": 0
},
{
"not": {
"field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.storageProfile.dataDisks[*].managedDisk.diskEncryptionSet.id",
"exists": "true"
}
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/disks"
},
{
"field": "Microsoft.Compute/disks/encryption.diskEncryptionSetId",
"exists": "False"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/galleries/images/versions"
},
{
"value": "[length(field('Microsoft.Compute/galleries/images/versions/publishingProfile.targetRegions[*].encryption.osDiskImage.diskEncryptionSetId'))]",
"notEquals": "[length(field('Microsoft.Compute/galleries/images/versions/publishingProfile.targetRegions[*]'))]"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/galleries/images/versions"
},
{
"value": "[length(field('Microsoft.Compute/galleries/images/versions/storageProfile.dataDiskImages[*]'))]",
"greater": 0
},
{
"anyOf": [
{
"count": {
"field": "Microsoft.Compute/galleries/images/versions/publishingProfile.targetRegions[*]",
"where": {
"value": "[length(current('Microsoft.Compute/galleries/images/versions/publishingProfile.targetRegions[*].encryption.dataDiskImages[*].diskEncryptionSetId'))]",
"notEquals": "[length(field('Microsoft.Compute/galleries/images/versions/storageProfile.dataDiskImages[*]'))]"
}
},
"greater": 0
},
{
"not": {
"field": "Microsoft.Compute/galleries/images/versions/publishingProfile.targetRegions[*].encryption.dataDiskImages[*].diskEncryptionSetId",
"exists": "true"
}
}
]
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/images"
},
{
"field": "Microsoft.Compute/images/storageProfile.osDisk.diskEncryptionSet.id",
"exists": "False"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/images"
},
{
"value": "[length(field('Microsoft.Compute/images/storageProfile.dataDisks[*]'))]",
"greater": 0
},
{
"not": {
"field": "Microsoft.Compute/images/storageProfile.dataDisks[*].diskEncryptionSet.id",
"exists": "true"
}
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
},
"versions": [
"3.0.0"
]
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/702dd420-7fcc-42c5-afe8-4026edd20fe0",
"name": "702dd420-7fcc-42c5-afe8-4026edd20fe0"
}
cases:
# =========================================================================
# 1. VM with CMK on OS disk → pass
# =========================================================================
- note: pass_vm_osdisk_with_cmk
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-with-cmk"
properties:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# 2. VM without CMK on OS disk → Audit
# =========================================================================
- note: audit_vm_osdisk_no_cmk
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-no-cmk"
properties:
storageProfile:
osDisk:
managedDisk:
storageAccountType: "Premium_LRS"
want_effect: "Audit"
# =========================================================================
# 3. VM with CMK on OS disk and data disks having CMK → pass
# =========================================================================
- note: pass_vm_osdisk_and_datadisks_with_cmk
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-all-cmk"
properties:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDisks:
- lun: 0
manageddisk:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/disks/datadisk0"
diskencryptionset:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- lun: 1
manageddisk:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/disks/datadisk1"
diskencryptionset:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# 4. VM with data disks missing CMK (no managedDisk.id and no
# diskEncryptionSet.id) → Audit
# =========================================================================
- note: audit_vm_datadisks_no_cmk
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-datadisks-no-cmk"
properties:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDisks:
- lun: 0
manageddisk:
storageaccounttype: "Premium_LRS"
- lun: 1
manageddisk:
storageaccounttype: "Standard_LRS"
want_effect: "Audit"
# =========================================================================
# 5. VMSS without CMK on OS disk → Audit
# =========================================================================
- note: audit_vmss_osdisk_no_cmk
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-no-cmk"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
managedDisk:
storageAccountType: "Premium_LRS"
want_effect: "Audit"
# =========================================================================
# 5b. VMSS with CMK on OS disk → pass
# =========================================================================
- note: pass_vmss_osdisk_with_cmk
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-with-cmk"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# 5c. VMSS with data disks missing CMK → Audit
# =========================================================================
- note: audit_vmss_datadisks_no_cmk
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-datadisks-no-cmk"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDisks:
- lun: 0
managedDisk:
storageAccountType: "Premium_LRS"
- lun: 1
managedDisk:
storageAccountType: "Standard_LRS"
want_effect: "Audit"
# =========================================================================
# 5d. VMSS with data disks having CMK → pass
# =========================================================================
- note: pass_vmss_datadisks_with_cmk
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-datadisks-cmk"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDisks:
- lun: 0
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- lun: 1
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# 6. Disk without diskEncryptionSetId → Audit
# =========================================================================
- note: audit_disk_no_des
resource:
type: "Microsoft.Compute/disks"
name: "disk-no-encryption"
properties:
diskSizeGB: 128
encryption:
type: "EncryptionAtRestWithPlatformKey"
want_effect: "Audit"
# =========================================================================
# 7. Disk with diskEncryptionSetId → pass
# =========================================================================
- note: pass_disk_with_des
resource:
type: "Microsoft.Compute/disks"
name: "disk-with-des"
properties:
diskSizeGB: 128
encryption:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
type: "EncryptionAtRestWithCustomerKey"
want_undefined: true
# =========================================================================
# 8. Image without CMK on OS disk → Audit
# =========================================================================
- note: audit_image_osdisk_no_cmk
resource:
type: "Microsoft.Compute/images"
name: "image-no-cmk"
properties:
storageProfile:
osDisk:
osType: "Linux"
osState: "Generalized"
want_effect: "Audit"
# =========================================================================
# 8b. Image with CMK on OS disk → pass
# =========================================================================
- note: pass_image_osdisk_with_cmk
resource:
type: "Microsoft.Compute/images"
name: "image-with-cmk"
properties:
storageProfile:
osDisk:
osType: "Linux"
osState: "Generalized"
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# 8c. Image with data disks missing CMK → Audit
# =========================================================================
- note: audit_image_datadisks_no_cmk
resource:
type: "Microsoft.Compute/images"
name: "image-datadisks-no-cmk"
properties:
storageProfile:
osDisk:
osType: "Linux"
osState: "Generalized"
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDisks:
- lun: 0
blobUri: "https://storage.blob.core.windows.net/vhds/datadisk.vhd"
- lun: 1
blobUri: "https://storage.blob.core.windows.net/vhds/datadisk2.vhd"
want_effect: "Audit"
# =========================================================================
# 8d. Image with data disks having CMK → pass
# =========================================================================
- note: pass_image_datadisks_with_cmk
resource:
type: "Microsoft.Compute/images"
name: "image-datadisks-cmk"
properties:
storageProfile:
osDisk:
osType: "Linux"
osState: "Generalized"
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDisks:
- lun: 0
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- lun: 1
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# Gallery Image Version: OS disk encryption (branch 6)
# =========================================================================
- note: audit_gallery_version_osdisk_no_cmk
resource:
type: "Microsoft.Compute/galleries/images/versions"
name: "gallery-version-osdisk-no-cmk"
properties:
publishingProfile:
targetRegions:
- name: "eastus"
- name: "westus"
want_effect: "Audit"
- note: pass_gallery_version_osdisk_with_cmk
resource:
type: "Microsoft.Compute/galleries/images/versions"
name: "gallery-version-osdisk-cmk"
properties:
publishingProfile:
targetRegions:
- name: "eastus"
encryption:
osDiskImage:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- name: "westus"
encryption:
osDiskImage:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# Gallery Image Version: data disk encryption (branch 7)
# =========================================================================
- note: audit_gallery_version_datadisks_no_cmk
resource:
type: "Microsoft.Compute/galleries/images/versions"
name: "gallery-version-datadisks-no-cmk"
properties:
storageProfile:
dataDiskImages:
- lun: 0
- lun: 1
publishingProfile:
targetRegions:
- name: "eastus"
encryption:
osDiskImage:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- name: "westus"
encryption:
osDiskImage:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_effect: "Audit"
- note: pass_gallery_version_datadisks_with_cmk
resource:
type: "Microsoft.Compute/galleries/images/versions"
name: "gallery-version-datadisks-cmk"
properties:
storageProfile:
dataDiskImages:
- lun: 0
- lun: 1
publishingProfile:
targetRegions:
- name: "eastus"
encryption:
osDiskImage:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDiskImages:
- diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- name: "westus"
encryption:
osDiskImage:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
dataDiskImages:
- diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
- diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/myDES"
want_undefined: true
# =========================================================================
# 9. Wrong resource type → pass
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "myStorage"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,162 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Container Instances/ContainerInstance_LogAnalytics_Append
# Real Azure Policy: "Configure diagnostics for container group to log analytics workspace"
# Source: regolator/policyDefinitions/Container Instances/ContainerInstance_LogAnalytics_Append.json
#
# Features exercised:
# - Append effect with details array (two fields)
# - exists "false" operator (multiple conditions)
# - Parameterized effect (Append/Disabled)
# - Parameters injected into details value
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure diagnostics for container group to log analytics workspace",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Append", "Disabled"],
"defaultValue": "Append"
},
"workspaceId": {
"type": "String",
"metadata": {
"displayName": "Workspace ID"
}
},
"workspaceKey": {
"type": "String",
"metadata": {
"displayName": "Workspace Key"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.ContainerInstance/containerGroups"
},
{
"field": "Microsoft.ContainerInstance/containerGroups/diagnostics.logAnalytics.workspaceId",
"exists": "false"
},
{
"field": "Microsoft.ContainerInstance/containerGroups/diagnostics.logAnalytics.workspaceKey",
"exists": "false"
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": [
{
"field": "Microsoft.ContainerInstance/containerGroups/diagnostics.logAnalytics.workspaceId",
"value": "[parameters('workspaceId')]"
},
{
"field": "Microsoft.ContainerInstance/containerGroups/diagnostics.logAnalytics.workspaceKey",
"value": "[parameters('workspaceKey')]"
}
]
}
}
}
}
cases:
# =========================================================================
# Both diagnostics fields missing → append
# =========================================================================
- note: append_both_missing
resource:
type: "Microsoft.ContainerInstance/containerGroups"
name: "cg-no-diag"
properties: {}
parameters:
workspaceId: "workspace-guid-123"
workspaceKey: "workspace-key-abc"
want_effect: "Append"
want_details:
- field: "Microsoft.ContainerInstance/containerGroups/diagnostics.logAnalytics.workspaceId"
value: "workspace-guid-123"
- field: "Microsoft.ContainerInstance/containerGroups/diagnostics.logAnalytics.workspaceKey"
value: "workspace-key-abc"
- note: append_diagnostics_empty
resource:
type: "Microsoft.ContainerInstance/containerGroups"
name: "cg-empty-diag"
properties:
diagnostics: {}
parameters:
workspaceId: "ws-id"
workspaceKey: "ws-key"
want_effect: "Append"
# =========================================================================
# One or both fields present → pass
# =========================================================================
- note: pass_workspace_id_present
resource:
type: "Microsoft.ContainerInstance/containerGroups"
name: "cg-has-id"
properties:
diagnostics:
logAnalytics:
workspaceId: "existing-id"
parameters:
workspaceId: "ws-id"
workspaceKey: "ws-key"
want_undefined: true
- note: pass_workspace_key_present
resource:
type: "Microsoft.ContainerInstance/containerGroups"
name: "cg-has-key"
properties:
diagnostics:
logAnalytics:
workspaceKey: "existing-key"
parameters:
workspaceId: "ws-id"
workspaceKey: "ws-key"
want_undefined: true
- note: pass_both_present
resource:
type: "Microsoft.ContainerInstance/containerGroups"
name: "cg-full-diag"
properties:
diagnostics:
logAnalytics:
workspaceId: "existing-id"
workspaceKey: "existing-key"
parameters:
workspaceId: "ws-id"
workspaceKey: "ws-key"
want_undefined: true
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "not-container"
properties: {}
parameters:
workspaceId: "ws-id"
workspaceKey: "ws-key"
want_undefined: true

View File

@@ -0,0 +1,238 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Cosmos DB/Cosmos_NetworkRulesExist_Audit
# Real Azure Policy: "Azure Cosmos DB accounts should have firewall rules"
# Source: regolator/policyDefinitions/Cosmos DB/Cosmos_NetworkRulesExist_Audit.json
#
# Features exercised:
# - 4-level nesting: allOf → anyOf → allOf → anyOf
# - 3 separate count expressions (ipRules, privateEndpointConnections)
# - exists "false" checks
# - count field without where (plain count)
# - count with where clause (privateLinkServiceConnectionState.status)
# - Deeply nested sub-resource array alias
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Azure Cosmos DB accounts should have firewall rules",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Audit", "Deny", "Disabled"],
"defaultValue": "Deny"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.DocumentDB/databaseAccounts"
},
{
"anyOf": [
{
"field": "Microsoft.DocumentDB/databaseAccounts/publicNetworkAccess",
"exists": "false"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/publicNetworkAccess",
"equals": "Enabled"
}
]
},
{
"anyOf": [
{
"field": "Microsoft.DocumentDB/databaseAccounts/isVirtualNetworkFilterEnabled",
"exists": "false"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/isVirtualNetworkFilterEnabled",
"equals": "false"
}
]
},
{
"allOf": [
{
"anyOf": [
{
"field": "Microsoft.DocumentDB/databaseAccounts/ipRules",
"exists": "false"
},
{
"count": {
"field": "Microsoft.DocumentDB/databaseAccounts/ipRules[*]"
},
"equals": 0
}
]
},
{
"anyOf": [
{
"field": "Microsoft.DocumentDB/databaseAccounts/ipRangeFilter",
"exists": "false"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/ipRangeFilter",
"equals": ""
}
]
},
{
"anyOf": [
{
"count": {
"field": "Microsoft.DocumentDB/databaseAccounts/privateEndpointConnections[*]",
"where": {
"field": "Microsoft.DocumentDB/databaseAccounts/privateEndpointConnections[*].privateLinkServiceConnectionState.status",
"equals": "Approved"
}
},
"less": 1
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Fully unprotected (public, no vnet filter, no ip rules, no PE) → deny
# =========================================================================
- note: deny_completely_open
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-open"
properties:
publicNetworkAccess: "Enabled"
isVirtualNetworkFilterEnabled: false
ipRules: []
ipRangeFilter: ""
privateEndpointConnections: []
want_effect: "Deny"
- note: deny_public_access_missing_fields
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-defaults"
properties: {}
want_effect: "Deny"
# =========================================================================
# Protected by disabling public access → pass
# =========================================================================
- note: pass_public_access_disabled
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-private"
properties:
publicNetworkAccess: "Disabled"
want_undefined: true
# =========================================================================
# Protected by vnet filter → pass
# =========================================================================
- note: pass_vnet_filter_enabled
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-vnet"
properties:
publicNetworkAccess: "Enabled"
isVirtualNetworkFilterEnabled: true
want_undefined: true
# =========================================================================
# Protected by IP rules → pass
# =========================================================================
- note: pass_has_ip_rules
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-ip"
properties:
publicNetworkAccess: "Enabled"
isVirtualNetworkFilterEnabled: false
ipRules:
- ipAddressOrRange: "10.0.0.1"
want_undefined: true
- note: pass_has_ip_range_filter
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-iprange"
properties:
publicNetworkAccess: "Enabled"
isVirtualNetworkFilterEnabled: false
ipRules: []
ipRangeFilter: "10.0.0.0/24"
want_undefined: true
# =========================================================================
# Protected by approved private endpoint → pass
# =========================================================================
- note: pass_approved_private_endpoint
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-pe"
properties:
publicNetworkAccess: "Enabled"
isVirtualNetworkFilterEnabled: false
ipRules: []
ipRangeFilter: ""
privateEndpointConnections:
- properties:
privateLinkServiceConnectionState:
status: "Approved"
want_undefined: true
# =========================================================================
# Private endpoint exists but not approved → deny
# =========================================================================
- note: deny_pending_private_endpoint
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-pe-pending"
properties:
publicNetworkAccess: "Enabled"
isVirtualNetworkFilterEnabled: false
ipRules: []
ipRangeFilter: ""
privateEndpointConnections:
- properties:
privateLinkServiceConnectionState:
status: "Pending"
want_effect: "Deny"
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-cosmos"
properties:
publicNetworkAccess: "Enabled"
want_undefined: true

View File

@@ -0,0 +1,170 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Cosmos DB/Cosmos_Locations_Deny
# Real Azure Policy: "Azure Cosmos DB allowed locations"
# Source: regolator/policyDefinitions/Cosmos DB/Cosmos_Locations_Deny.json
#
# Features exercised:
# - count with where clause
# - Chained template functions in where: replace(toLower(first(field(...))), ' ', '')
# - count result compared to length(field(...)) via notEquals
# - Parameterized effect with case-variant allowedValues
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Azure Cosmos DB allowed locations",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"listOfAllowedLocations": {
"type": "Array",
"metadata": {
"displayName": "Allowed locations",
"strongType": "location"
}
},
"policyEffect": {
"type": "String",
"allowedValues": ["audit", "Audit", "deny", "Deny", "disabled", "Disabled"],
"defaultValue": "Deny"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.DocumentDB/databaseAccounts"
},
{
"count": {
"field": "Microsoft.DocumentDB/databaseAccounts/Locations[*]",
"where": {
"value": "[replace(toLower(first(field('Microsoft.DocumentDB/databaseAccounts/Locations[*].locationName'))), ' ', '')]",
"in": "[parameters('listOfAllowedLocations')]"
}
},
"notEquals": "[length(field('Microsoft.DocumentDB/databaseAccounts/Locations[*]'))]"
}
]
},
"then": {
"effect": "[parameters('policyEffect')]"
}
}
}
}
cases:
# =========================================================================
# All locations allowed → pass
# =========================================================================
- note: pass_all_locations_in_allowed_list
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-compliant"
properties:
Locations:
- locationName: "East US"
- locationName: "West US"
parameters:
listOfAllowedLocations: ["eastus", "westus"]
want_undefined: true
- note: pass_single_location_allowed
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-single"
properties:
Locations:
- locationName: "East US"
parameters:
listOfAllowedLocations: ["eastus", "westus", "centralus"]
want_undefined: true
# =========================================================================
# Location not in allowed list → deny
# =========================================================================
- note: deny_location_not_allowed
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-bad-region"
properties:
Locations:
- locationName: "East US"
- locationName: "North Europe"
parameters:
listOfAllowedLocations: ["eastus", "westus"]
want_effect: "Deny"
- note: deny_all_locations_disallowed
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-all-bad"
properties:
Locations:
- locationName: "South East Asia"
- locationName: "Japan East"
parameters:
listOfAllowedLocations: ["eastus", "westus"]
want_effect: "Deny"
- note: deny_one_of_three_disallowed
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-one-bad"
properties:
Locations:
- locationName: "East US"
- locationName: "West US"
- locationName: "Brazil South"
parameters:
listOfAllowedLocations: ["eastus", "westus"]
want_effect: "Deny"
# =========================================================================
# Edge: location names with spaces normalized by replace+toLower
# =========================================================================
- note: pass_location_with_spaces_normalized
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-spaces"
properties:
Locations:
- locationName: "Central US"
parameters:
listOfAllowedLocations: ["centralus"]
want_undefined: true
- note: pass_mixed_case_location
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-case"
properties:
Locations:
- locationName: "EAST US"
parameters:
listOfAllowedLocations: ["eastus"]
want_undefined: true
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-cosmos"
properties:
Locations:
- locationName: "East US"
parameters:
listOfAllowedLocations: ["westus"]
want_undefined: true

View File

@@ -0,0 +1,445 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Cosmos DB/Cosmos_MaxThroughput_Deny
# Real Azure Policy: "Azure Cosmos DB throughput should be limited"
# Source: regolator/policyDefinitions/Cosmos DB/Cosmos_MaxThroughput_Deny.json
#
# Features exercised:
# - allOf with nested anyOf (type check + condition check)
# - type "like" pattern matching (*/throughputSettings)
# - type "in" with 9 resource types
# - Template expressions: if(), equals(), int(), field()
# - containsKey operator
# - exists operator
# - greater operator with parameterized threshold
# - Parameters: throughputMax (Integer), effect (String)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Azure Cosmos DB throughput should be limited",
"policyType": "BuiltIn",
"mode": "All",
"description": "This policy enables you to restrict the maximum throughput your organization can specify when creating Azure Cosmos DB databases and containers through the resource provider. It blocks the creation of autoscale resources.",
"metadata": {
"version": "1.1.0",
"category": "Cosmos DB"
},
"version": "1.1.0",
"parameters": {
"throughputMax": {
"type": "Integer",
"metadata": {
"displayName": "Max RUs",
"description": "The maximum throughput (RU/s) that can be assigned to a container via the Resource Provider during create or update."
}
},
"effect": {
"type": "String",
"metadata": {
"displayName": "Policy Effect",
"description": "The desired effect of the policy."
},
"allowedValues": [
"audit",
"Audit",
"deny",
"Deny",
"disabled",
"Disabled"
],
"defaultValue": "Deny"
}
},
"policyRule": {
"if": {
"allOf": [
{
"anyOf": [
{
"field": "type",
"like": "Microsoft.DocumentDB/databaseAccounts/*/throughputSettings"
},
{
"field": "type",
"in": [
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
"Microsoft.DocumentDB/databaseAccounts/mongodbDatabases",
"Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections",
"Microsoft.DocumentDB/databaseAccounts/gremlinDatabases",
"Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs",
"Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces",
"Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables",
"Microsoft.DocumentDB/databaseAccounts/tables"
]
}
]
},
{
"anyOf": [
{
"value": "[requestContext().apiVersion]",
"less": "2019-08-01"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
},
{
"value": "[if(equals(field('Microsoft.DocumentDB/databaseAccounts/tables/options.throughput'), ''), 0, int(field('Microsoft.DocumentDB/databaseAccounts/tables/options.throughput')))]",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/tables/options",
"containsKey": "ProvisionedThroughputSettings"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/tables/throughputSettings/default.resource.throughput",
"greater": "[parameters('throughputMax')]"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/tables/throughputSettings/default.resource.provisionedThroughputSettings",
"exists": "true"
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
},
"versions": [
"1.1.0"
]
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/0b7ef78e-a035-4f23-b9bd-aff122a1b1cf",
"name": "0b7ef78e-a035-4f23-b9bd-aff122a1b1cf"
}
cases:
# =========================================================================
# SQL Database: options.throughput exceeds max → Deny
# =========================================================================
- note: deny_sql_db_throughput_exceeds_max
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases"
name: "test-db"
properties:
options:
throughput: "600"
want_effect: "Deny"
# =========================================================================
# SQL Database: options.throughput within max → pass
# =========================================================================
- note: pass_sql_db_throughput_within_max
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases"
name: "test-db-ok"
properties:
options:
throughput: "200"
want_undefined: true
# =========================================================================
# SQL Database: autoscale (ProvisionedThroughputSettings key) → Deny
# =========================================================================
- note: deny_sql_db_autoscale
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases"
name: "test-db-autoscale"
properties:
options:
ProvisionedThroughputSettings:
maxThroughput: 4000
want_effect: "Deny"
# =========================================================================
# Container: options.throughput exceeds max → Deny
# =========================================================================
- note: deny_container_throughput_exceeds_max
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
name: "test-container"
properties:
options:
throughput: "600"
want_effect: "Deny"
# =========================================================================
# Wrong type (parent databaseAccounts, not a sub-resource) → pass
# =========================================================================
- note: pass_wrong_type
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "test-account"
properties: {}
want_undefined: true
# =========================================================================
# MongoDB: throughputSettings throughput exceeds max → Deny
# =========================================================================
- note: deny_mongodb_throughput_settings
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases"
name: "test-mongo"
properties:
"default":
resource:
throughput: 600
want_effect: "Deny"
# =========================================================================
# Tables: throughputSettings autoscale (provisionedThroughputSettings) → Deny
# =========================================================================
- note: deny_table_autoscale
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/tables"
name: "test-table"
properties:
"default":
resource:
provisionedThroughputSettings:
maxThroughput: 4000
want_effect: "Deny"
# =========================================================================
# Container: empty options.throughput → evaluates to 0 → pass
# =========================================================================
- note: pass_container_no_throughput
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
name: "test-container-empty"
properties:
options:
throughput: ""
want_undefined: true
# =========================================================================
# Cassandra Keyspace: options.throughput exceeds max → Deny
# =========================================================================
- note: deny_cassandra_keyspace_throughput
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces"
name: "test-cassandra-ks"
properties:
options:
throughput: "600"
want_effect: "Deny"
# =========================================================================
# Cassandra Table: options.throughput exceeds max → Deny
# =========================================================================
- note: deny_cassandra_table_throughput
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/cassandraKeyspaces/tables"
name: "test-cassandra-table"
properties:
options:
throughput: "600"
want_effect: "Deny"
# =========================================================================
# Gremlin Database: options.throughput exceeds max → Deny
# =========================================================================
- note: deny_gremlin_database_throughput
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases"
name: "test-gremlin-db"
properties:
options:
throughput: "600"
want_effect: "Deny"
# =========================================================================
# Gremlin Graph: autoscale (ProvisionedThroughputSettings key) → Deny
# =========================================================================
- note: deny_gremlin_graph_autoscale
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs"
name: "test-gremlin-graph"
properties:
options:
ProvisionedThroughputSettings:
maxThroughput: 4000
want_effect: "Deny"
# =========================================================================
# MongoDB Collection: options.throughput exceeds max → Deny
# =========================================================================
- note: deny_mongo_collection_throughput
parameters:
throughputMax: 400
resource:
type: "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections"
name: "test-mongo-collection"
properties:
options:
throughput: "600"
want_effect: "Deny"

View File

@@ -0,0 +1,118 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Cosmos DB/Cosmos_PrivateNetworkAccess_Modify
# Real Azure Policy: "Configure CosmosDB accounts to disable public network access"
# Source: regolator/policyDefinitions/Cosmos DB/Cosmos_PrivateNetworkAccess_Modify.json
#
# Features exercised:
# - Modify effect with requestContext().apiVersion condition on operation
# - greaterOrEquals on API version string
# - conflictEffect in details
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure CosmosDB accounts to disable public network access",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Modify", "Disabled"],
"defaultValue": "Modify"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.DocumentDB/databaseAccounts"
},
{
"field": "Microsoft.DocumentDB/databaseAccounts/publicNetworkAccess",
"notEquals": "Disabled"
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
"/providers/Microsoft.Authorization/roleDefinitions/5bd9cd88-fe45-4216-938b-f97437e15450"
],
"conflictEffect": "audit",
"operations": [
{
"condition": "[greaterOrEquals(requestContext().apiVersion, '2021-01-15')]",
"operation": "addOrReplace",
"field": "Microsoft.DocumentDB/databaseAccounts/publicNetworkAccess",
"value": "Disabled"
}
]
}
}
}
}
}
cases:
# =========================================================================
# Public access enabled → modify
# =========================================================================
- note: modify_public_access_enabled
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-public"
properties:
publicNetworkAccess: "Enabled"
api_version: "2023-04-15"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
- "/providers/Microsoft.Authorization/roleDefinitions/5bd9cd88-fe45-4216-938b-f97437e15450"
operations:
- condition: "[greaterOrEquals(requestContext().apiVersion, '2021-01-15')]"
operation: "addOrReplace"
field: "Microsoft.DocumentDB/databaseAccounts/publicNetworkAccess"
value: "Disabled"
- note: modify_public_access_missing
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-no-field"
properties: {}
api_version: "2023-04-15"
want_effect: "Modify"
# =========================================================================
# Public access already disabled → pass
# =========================================================================
- note: pass_public_access_disabled
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
name: "cosmos-disabled"
properties:
publicNetworkAccess: "Disabled"
api_version: "2023-04-15"
want_undefined: true
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-cosmos"
properties:
publicNetworkAccess: "Enabled"
api_version: "2023-04-15"
want_undefined: true

View File

@@ -0,0 +1,231 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: General/CustomSubscription_OwnerRole_Audit
# Real Azure Policy: "[Deprecated]: Custom subscription owner roles should not exist"
# Source: regolator/policyDefinitions/General/CustomSubscription_OwnerRole_Audit.json
#
# Features exercised:
# - 4 double-negation blocks: not { field notEquals }, not { field notIn }, not { field notLike }
# - Array wildcard aliases: permissions[*].actions[*], assignableScopes[*]
# - subscription().id and concat(subscription().id, '/')
# - notLike "/providers/Microsoft.Management/*"
# - Deeply nested sub-resource arrays (permissions[*].actions[*])
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Deprecated]: Custom subscription owner roles should not exist",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Authorization/roleDefinitions"
},
{
"field": "Microsoft.Authorization/roleDefinitions/type",
"equals": "CustomRole"
},
{
"anyOf": [
{
"not": {
"field": "Microsoft.Authorization/roleDefinitions/permissions[*].actions[*]",
"notEquals": "*"
}
}
]
},
{
"anyOf": [
{
"not": {
"field": "Microsoft.Authorization/roleDefinitions/assignableScopes[*]",
"notIn": [
"[concat(subscription().id,'/')]",
"[subscription().id]",
"/"
]
}
},
{
"not": {
"field": "Microsoft.Authorization/roleDefinitions/assignableScopes[*]",
"notLike": "/providers/Microsoft.Management/*"
}
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Custom owner role with subscription scope → audit
# =========================================================================
- note: audit_custom_owner_subscription_scope
resource:
type: "Microsoft.Authorization/roleDefinitions"
name: "custom-owner"
properties:
type: "CustomRole"
permissions:
- actions:
- "*"
assignableScopes:
- "/subscriptions/sub-123"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_effect: "Audit"
- note: audit_custom_owner_subscription_trailing_slash
resource:
type: "Microsoft.Authorization/roleDefinitions"
name: "custom-owner-slash"
properties:
type: "CustomRole"
permissions:
- actions:
- "*"
assignableScopes:
- "/subscriptions/sub-123/"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_effect: "Audit"
- note: audit_custom_owner_root_scope
resource:
type: "Microsoft.Authorization/roleDefinitions"
name: "custom-owner-root"
properties:
type: "CustomRole"
permissions:
- actions:
- "*"
assignableScopes:
- "/"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_effect: "Audit"
- note: audit_custom_owner_management_group_scope
resource:
type: "Microsoft.Authorization/roleDefinitions"
name: "custom-owner-mg"
properties:
type: "CustomRole"
permissions:
- actions:
- "*"
assignableScopes:
- "/providers/Microsoft.Management/managementGroups/mg1"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_effect: "Audit"
# =========================================================================
# Custom role without owner (*) actions → pass
# =========================================================================
- note: pass_custom_role_no_wildcard_actions
resource:
type: "Microsoft.Authorization/roleDefinitions"
name: "custom-reader"
properties:
type: "CustomRole"
permissions:
- actions:
- "Microsoft.Compute/virtualMachines/read"
- "Microsoft.Storage/storageAccounts/read"
assignableScopes:
- "/subscriptions/sub-123"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_undefined: true
# =========================================================================
# Custom owner role but NOT scoped to subscription/root/MG → pass
# =========================================================================
- note: pass_custom_owner_resource_group_scope
resource:
type: "Microsoft.Authorization/roleDefinitions"
name: "custom-owner-rg"
properties:
type: "CustomRole"
permissions:
- actions:
- "*"
assignableScopes:
- "/subscriptions/sub-123/resourceGroups/rg1"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_undefined: true
# =========================================================================
# BuiltIn role (not CustomRole) → pass
# =========================================================================
- note: pass_builtin_role
resource:
type: "Microsoft.Authorization/roleDefinitions"
name: "builtin-owner"
properties:
type: "BuiltInRole"
permissions:
- actions:
- "*"
assignableScopes:
- "/"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_undefined: true
# =========================================================================
# Wrong resource type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "not-role-def"
properties:
type: "CustomRole"
context:
subscription:
subscriptionId: "sub-123"
id: "/subscriptions/sub-123"
want_undefined: true

View File

@@ -0,0 +1,458 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Data Factory/LinkedService_InlineSecrets_Audit
# Real Azure Policy: "Azure Data Factory linked services should use Key Vault for storing secrets"
# Source: regolator/policyDefinitions/Data Factory/LinkedService_InlineSecrets_Audit.json
#
# Features exercised:
# - Large anyOf with 20+ branches
# - "contains" operator for secret keywords in connectionString
# - "exists" checks for secret fields
# - "equals" / "notEquals" / "in" checks for .type field (SecureString vs AzureKeyVaultSecret)
# - Service-type-prefixed aliases (SqlServer., AzureStorage., etc.)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Azure Data Factory linked services should use Key Vault for storing secrets",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Audit", "Deny", "Disabled"],
"defaultValue": "Audit"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.DataFactory/factories/linkedservices"
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
"exists": "true"
},
{
"anyOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
"contains": "AccountKey="
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
"contains": "PWD="
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
"contains": "Password="
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
"contains": "CredString="
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString",
"contains": "pwd="
}
]
}
]
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/SqlServer.typeProperties.password.type",
"equals": "SecureString"
},
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/SqlServer.typeProperties.password",
"exists": "true"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/SqlServer.typeProperties.password.type",
"exists": "false"
}
]
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/AzureSqlDW.typeProperties.servicePrincipalKey.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/AzureSearch.typeProperties.key.type",
"equals": "SecureString"
},
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/AzureStorage.typeProperties.sasUri",
"exists": "true"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/AzureStorage.typeProperties.sasUri.type",
"notEquals": "AzureKeyVaultSecret"
}
]
},
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/AzureBlobStorage.typeProperties.servicePrincipalKey",
"exists": "true"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/AzureBlobStorage.typeProperties.servicePrincipalKey.type",
"notEquals": "AzureKeyVaultSecret"
}
]
},
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/AzureStorage.typeProperties.accountKey",
"exists": "true"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/CosmosDb.typeProperties.accountKey.type",
"notEquals": "AzureKeyVaultSecret"
}
]
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.encryptedCredential",
"exists": "true"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/AmazonMWS.typeProperties.mwsAuthToken.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/AmazonMWS.typeProperties.secretKey.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/AmazonS3.typeProperties.secretAccessKey.type",
"equals": "SecureString"
},
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/Dynamics.typeProperties.servicePrincipalCredential",
"exists": "true"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/Dynamics.typeProperties.servicePrincipalCredential.type",
"equals": "SecureString"
}
]
},
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/Hubspot.typeProperties.accessToken",
"exists": "true"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/Hubspot.typeProperties.accessToken.type",
"equals": "SecureString"
}
]
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/Odbc.typeProperties.credential.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/GoogleAdWords.typeProperties.developerToken.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/GoogleBigQuery.typeProperties.clientSecret.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/GoogleBigQuery.typeProperties.refreshToken.type",
"equals": "SecureString"
},
{
"allOf": [
{
"field": "Microsoft.DataFactory/factories/linkedservices/type",
"in": [
"MongoDbAtlas",
"MongoDbV2"
]
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/typeProperties.connectionString.type",
"notEquals": "AzureKeyVaultSecret"
}
]
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/OData.typeProperties.servicePrincipalEmbeddedCert.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/OData.typeProperties.servicePrincipalEmbeddedCertPassword.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/Sftp.typeProperties.privateKeyContent.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/Sftp.typeProperties.passPhrase.type",
"equals": "SecureString"
},
{
"field": "Microsoft.DataFactory/factories/linkedservices/Salesforce.typeProperties.securityToken.type",
"equals": "SecureString"
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# connectionString contains "Password=" → Audit
# =========================================================================
- note: audit_connection_string_with_password
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-sql-inline-password"
properties:
type: SqlServer
typeProperties:
connectionString: "Server=myserver.database.windows.net;Database=mydb;User ID=admin;Password=secret123"
want_effect: "Audit"
# =========================================================================
# connectionString without secret keywords → pass
# =========================================================================
- note: pass_connection_string_no_secrets
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-sql-integrated"
properties:
type: SqlServer
typeProperties:
connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
want_undefined: true
# =========================================================================
# SqlServer password.type = SecureString → Audit
# =========================================================================
- note: audit_sql_server_secure_string
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-sql-securestring"
properties:
type: SqlServer
typeProperties:
connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
password:
type: SecureString
value: "my-password"
want_effect: "Audit"
# =========================================================================
# SqlServer password.type = AzureKeyVaultSecret → pass
# =========================================================================
- note: pass_sql_server_keyvault
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-sql-keyvault"
properties:
type: SqlServer
typeProperties:
connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
password:
type: AzureKeyVaultSecret
store:
referenceName: myKeyVault
type: LinkedServiceReference
secretName: mySecret
want_undefined: true
# =========================================================================
# encryptedCredential exists → Audit
# =========================================================================
- note: audit_encrypted_credential
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-encrypted"
properties:
type: AzureBlobStorage
typeProperties:
connectionString: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net"
encryptedCredential: "eyJWZXJzaW9uIj..."
want_effect: "Audit"
# =========================================================================
# No secrets at all → pass
# =========================================================================
- note: pass_no_secrets
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-clean"
properties:
type: AzureBlobFS
typeProperties:
url: "https://mydatalake.dfs.core.windows.net"
want_undefined: true
# =========================================================================
# Wrong resource type → pass
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-data-factory"
properties:
supportsHttpsTrafficOnly: true
want_undefined: true
# =========================================================================
# AzureStorage sasUri exists but type not AzureKeyVaultSecret → Audit
# =========================================================================
- note: audit_storage_sas_no_keyvault
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-storage-inline-sas"
properties:
type: AzureStorage
typeProperties:
sasUri: "https://mystorage.blob.core.windows.net/?sv=2020-08-04&ss=b&srt=sco&sp=rwdlacupx"
want_effect: "Audit"
# =========================================================================
# AzureSqlDW servicePrincipalKey.type = SecureString → Audit
# =========================================================================
- note: audit_azure_sql_dw_spkey_securestring
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-sqldw-spkey"
properties:
type: AzureSqlDW
typeProperties:
connectionString: "Server=myserver.database.windows.net;Database=mydb;Integrated Security=true"
servicePrincipalKey:
type: SecureString
value: "my-sp-key"
want_effect: "Audit"
# =========================================================================
# AzureStorage accountKey exists + type != AzureKeyVaultSecret → Audit
# =========================================================================
- note: audit_storage_accountkey_not_keyvault
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-storage-accountkey"
properties:
type: AzureStorage
typeProperties:
connectionString: "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net"
accountKey:
type: SecureString
value: "base64accountkey=="
want_effect: "Audit"
# =========================================================================
# MongoDbAtlas connectionString.type != AzureKeyVaultSecret → Audit
# =========================================================================
- note: audit_mongodbatlas_connstr_not_keyvault
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-mongodbatlas-inline"
properties:
type: MongoDbAtlas
typeProperties:
connectionString:
type: SecureString
value: "mongodb+srv://user:pass@cluster0.mongodb.net/mydb"
database: mydb
want_effect: "Audit"
# =========================================================================
# AmazonS3 secretAccessKey.type = SecureString → Audit
# =========================================================================
- note: audit_amazon_s3_secret_securestring
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-amazons3-secret"
properties:
type: AmazonS3
typeProperties:
accessKeyId: "AKIAIOSFODNN7EXAMPLE"
secretAccessKey:
type: SecureString
value: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
want_effect: "Audit"
# =========================================================================
# Sftp privateKeyContent.type = SecureString → Audit
# =========================================================================
- note: audit_sftp_privatekey_securestring
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-sftp-privatekey"
properties:
type: Sftp
typeProperties:
host: "sftp.example.com"
userName: "sftpuser"
privateKeyContent:
type: SecureString
value: "-----BEGIN RSA PRIVATE KEY-----..."
want_effect: "Audit"
# =========================================================================
# Odbc credential.type = AzureKeyVaultSecret → pass (not SecureString)
# =========================================================================
- note: pass_odbc_credential_keyvault
resource:
type: "Microsoft.DataFactory/factories/linkedservices"
name: "adf-odbc-keyvault"
properties:
type: Odbc
typeProperties:
connectionString: "Driver={SQL Server};Server=myserver;Database=mydb"
credential:
type: AzureKeyVaultSecret
store:
referenceName: myKeyVault
type: LinkedServiceReference
secretName: odbcCredential
want_undefined: true

View File

@@ -0,0 +1,757 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Monitoring/AzureMonitor_DCRA_VMSS_Linux_DINE
# Real Azure Policy: "Configure Linux Virtual Machine Scale Sets to be associated
# with a Data Collection Rule or a Data Collection Endpoint"
# Source: regolator/policyDefinitions/Monitoring/AzureMonitor_DCRA_VMSS_Linux_DINE.json
#
# Features exercised:
# - 78 condition nodes, 611 lines — representative of ~30 Monitoring/* policies
# - Boolean parameter (scopeToSupportedImages)
# - Polymorphic resourceType parameter (DCR vs DCE)
# - DeployIfNotExists with conditional deployment
# - existenceCondition with anyOf
# - Large hardcoded region list (60+ locations)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure Linux Virtual Machine Scale Sets to be associated with a Data Collection Rule or a Data Collection Endpoint",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Deploy Association to link Linux virtual machine scale sets to the specified Data Collection Rule or the specified Data Collection Endpoint. The list of locations and OS images are updated over time as support is increased.",
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy."
},
"allowedValues": [
"DeployIfNotExists",
"Disabled"
],
"defaultValue": "DeployIfNotExists"
},
"scopeToSupportedImages": {
"type": "Boolean",
"metadata": {
"displayName": "Scope Policy to Azure Monitor Agent-Supported Operating Systems",
"description": "If set to true, the policy will apply only to virtual machine scale sets with AMA-supported operating systems. Otherwise, the policy will apply to all virtual machine scale set resources in the assignment scope. For supported operating systems, see https://aka.ms/AMAOverview."
},
"allowedValues": [
true,
false
],
"defaultValue": true
},
"listOfLinuxImageIdToInclude": {
"type": "Array",
"metadata": {
"displayName": "Additional Linux Machine Images",
"description": "List of virtual machine scale set images that have supported Linux OS to add to scope. Example values: '/subscriptions/<subscriptionId>/resourceGroups/YourResourceGroup/providers/Microsoft.Compute/images/ContosoStdImage'"
},
"defaultValue": []
},
"dcrResourceId": {
"type": "String",
"metadata": {
"displayName": "Data Collection Rule Resource Id or Data Collection Endpoint Resource Id",
"description": "Resource Id of the Data Collection Rule or the Data Collection Endpoint to be applied on the Linux machines in scope.",
"portalReview": "true",
"assignPermissions": true
}
},
"resourceType": {
"type": "String",
"metadata": {
"displayName": "Resource Type",
"description": "Either a Data Collection Rule (DCR) or a Data Collection Endpoint (DCE)",
"portalReview": "true"
},
"allowedValues": [
"Microsoft.Insights/dataCollectionRules",
"Microsoft.Insights/dataCollectionEndpoints"
],
"defaultValue": "Microsoft.Insights/dataCollectionRules"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachineScaleSets"
},
{
"field": "location",
"in": [
"australiacentral",
"australiacentral2",
"australiaeast",
"australiasoutheast",
"brazilsouth",
"brazilsoutheast",
"canadacentral",
"canadaeast",
"centralindia",
"centralus",
"centraluseuap",
"eastasia",
"eastus",
"eastus2",
"eastus2euap",
"francecentral",
"francesouth",
"germanynorth",
"germanywestcentral",
"israelcentral",
"italynorth",
"japaneast",
"japanwest",
"jioindiacentral",
"jioindiawest",
"koreacentral",
"koreasouth",
"malaysiasouth",
"mexicocentral",
"northcentralus",
"northeurope",
"norwayeast",
"norwaywest",
"polandcentral",
"qatarcentral",
"southafricanorth",
"southafricawest",
"southcentralus",
"southeastasia",
"southindia",
"spaincentral",
"swedencentral",
"swedensouth",
"switzerlandnorth",
"switzerlandwest",
"taiwannorth",
"taiwannorthwest",
"uaecentral",
"uaenorth",
"uksouth",
"ukwest",
"westcentralus",
"westeurope",
"westindia",
"westus",
"westus2",
"westus3"
]
},
{
"anyOf": [
{
"allOf": [
{
"value": "[parameters('scopeToSupportedImages')]",
"equals": false
},
{
"field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.storageProfile.osDisk.osType",
"like": "Linux*"
}
]
},
{
"field": "Microsoft.Compute/imageId",
"in": "[parameters('listOfLinuxImageIdToInclude')]"
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "RedHat"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"RHEL",
"RHEL-ARM64",
"RHEL-BYOS",
"RHEL-HA",
"RHEL-SAP",
"RHEL-SAP-APPS",
"RHEL-SAP-HA"
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSku",
"like": "7*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "8*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "9*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "rhel-lvm7*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "rhel-lvm8*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "rhel-lvm9*"
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "SUSE"
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"SLES",
"SLES-HPC",
"SLES-HPC-Priority",
"SLES-SAP",
"SLES-SAP-BYOS",
"SLES-Priority",
"SLES-BYOS",
"SLES-SAPCAL",
"SLES-Standard"
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSku",
"like": "12*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "15*"
}
]
}
]
},
{
"allOf": [
{
"anyOf": [
{
"field": "Microsoft.Compute/imageOffer",
"like": "sles-12*"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "sles-15*"
}
]
},
{
"field": "Microsoft.Compute/imageSku",
"in": [
"gen1",
"gen2"
]
}
]
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Canonical"
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageOffer",
"equals": "UbuntuServer"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "0001-com-ubuntu-server-*"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "0001-com-ubuntu-pro-*"
}
]
},
{
"field": "Microsoft.Compute/imageSku",
"in": [
"14.04.0-lts",
"14.04.1-lts",
"14.04.2-lts",
"14.04.3-lts",
"14.04.4-lts",
"14.04.5-lts",
"16_04_0-lts-gen2",
"16_04-lts-gen2",
"16.04-lts",
"16.04.0-lts",
"18_04-lts-arm64",
"18_04-lts-gen2",
"18.04-lts",
"20_04-lts-arm64",
"20_04-lts-gen2",
"20_04-lts",
"22_04-lts-gen2",
"22_04-lts",
"pro-16_04-lts-gen2",
"pro-16_04-lts",
"pro-18_04-lts-gen2",
"pro-18_04-lts",
"pro-20_04-lts-gen2",
"pro-20_04-lts",
"pro-22_04-lts-gen2",
"pro-22_04-lts"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Oracle"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "Oracle-Linux"
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSku",
"like": "7*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "8*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "ol7*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "ol8*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "ol9*"
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "OpenLogic"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"CentOS",
"Centos-LVM",
"CentOS-SRIOV"
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSku",
"like": "7*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "8*"
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "cloudera"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "cloudera-centos-os"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "7*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "almalinux"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "almalinux*"
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSku",
"like": "8*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "9*"
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "ctrliqinc1648673227698"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "rocky-8*"
},
{
"field": "Microsoft.Compute/imageSku",
"like": "rocky-8*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "credativ"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"Debian"
]
},
{
"field": "Microsoft.Compute/imageSku",
"equals": "9"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Debian"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"debian-10",
"debian-11"
]
},
{
"field": "Microsoft.Compute/imageSku",
"in": [
"10",
"10-gen2",
"11",
"11-gen2"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoftcblmariner"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "cbl-mariner"
},
{
"field": "Microsoft.Compute/imageSku",
"in": [
"1-gen2",
"cbl-mariner-1",
"cbl-mariner-2",
"cbl-mariner-2-arm64",
"cbl-mariner-2-gen2"
]
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Insights/dataCollectionRuleAssociations",
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa",
"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293"
],
"evaluationDelay": "AfterProvisioning",
"existenceCondition": {
"anyOf": [
{
"field": "Microsoft.Insights/dataCollectionRuleAssociations/dataCollectionRuleId",
"equals": "[parameters('dcrResourceId')]"
},
{
"field": "Microsoft.Insights/dataCollectionRuleAssociations/dataCollectionEndpointId",
"equals": "[parameters('dcrResourceId')]"
}
]
},
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceName": {
"type": "string"
},
"location": {
"type": "string"
},
"dcrResourceId": {
"type": "string"
},
"resourceType": {
"type": "string"
}
},
"variables": {
"dcrAssociationName": "[concat('assoc-', uniqueString(concat(parameters('resourceName'), parameters('dcrResourceId'))))]",
"dceAssociationName": "configurationAccessEndpoint",
"dcrResourceType": "Microsoft.Insights/dataCollectionRules",
"dceResourceType": "Microsoft.Insights/dataCollectionEndpoints"
},
"resources": [
{
"condition": "[equals(parameters('resourceType'), variables('dcrResourceType'))]",
"name": "[variables('dcrAssociationName')]",
"type": "Microsoft.Insights/dataCollectionRuleAssociations",
"apiVersion": "2021-04-01",
"properties": {
"dataCollectionRuleId": "[parameters('dcrResourceId')]"
},
"scope": "[concat('Microsoft.Compute/virtualMachineScaleSets/', parameters('resourceName'))]"
},
{
"condition": "[equals(parameters('resourceType'), variables('dceResourceType'))]",
"name": "[variables('dceAssociationName')]",
"type": "Microsoft.Insights/dataCollectionRuleAssociations",
"apiVersion": "2021-04-01",
"properties": {
"dataCollectionEndpointId": "[parameters('dcrResourceId')]"
},
"scope": "[concat('Microsoft.Compute/virtualMachineScaleSets/', parameters('resourceName'))]"
}
]
},
"parameters": {
"resourceName": {
"value": "[field('name')]"
},
"location": {
"value": "[field('location')]"
},
"dcrResourceId": {
"value": "[parameters('dcrResourceId')]"
},
"resourceType": {
"value": "[parameters('resourceType')]"
}
}
}
}
}
}
}
}
}
cases:
# =========================================================================
# DINE - Linux VMSS with Canonical/UbuntuServer image, no DCRA
# =========================================================================
- note: dine_vmss_canonical_ubuntu
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-ubuntu"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachineScaleSets/vmss-ubuntu"
location: "eastus"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
osType: "Linux"
imageReference:
publisher: "Canonical"
offer: "UbuntuServer"
sku: "18.04-lts"
parameters:
dcrResourceId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Insights/dataCollectionRules/dcr1"
effect: "DeployIfNotExists"
scopeToSupportedImages: true
listOfLinuxImageIdToInclude: []
resourceType: "Microsoft.Insights/dataCollectionRules"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Insights/dataCollectionRuleAssociations"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Pass - Windows VMSS (wrong OS type)
# =========================================================================
- note: pass_wrong_os_type
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-windows"
location: "eastus"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
osType: "Windows"
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
parameters:
dcrResourceId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Insights/dataCollectionRules/dcr1"
effect: "DeployIfNotExists"
scopeToSupportedImages: true
listOfLinuxImageIdToInclude: []
resourceType: "Microsoft.Insights/dataCollectionRules"
want_undefined: true
# =========================================================================
# DINE - VMSS with unsupported publisher but scopeToSupportedImages=false
# =========================================================================
- note: dine_vmss_scope_bypass
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-custom"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachineScaleSets/vmss-custom"
location: "eastus"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
osType: "Linux"
imageReference:
publisher: "CustomPublisher"
offer: "CustomLinux"
sku: "1.0"
parameters:
dcrResourceId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Insights/dataCollectionRules/dcr1"
effect: "DeployIfNotExists"
scopeToSupportedImages: false
listOfLinuxImageIdToInclude: []
resourceType: "Microsoft.Insights/dataCollectionRules"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Insights/dataCollectionRuleAssociations"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Pass - unsupported publisher with scopeToSupportedImages=true
# =========================================================================
- note: pass_unsupported_publisher_scoped
resource:
type: "Microsoft.Compute/virtualMachineScaleSets"
name: "vmss-custom-scoped"
location: "eastus"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
osType: "Linux"
imageReference:
publisher: "CustomPublisher"
offer: "CustomLinux"
sku: "1.0"
parameters:
dcrResourceId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Insights/dataCollectionRules/dcr1"
effect: "DeployIfNotExists"
scopeToSupportedImages: true
listOfLinuxImageIdToInclude: []
resourceType: "Microsoft.Insights/dataCollectionRules"
want_undefined: true
# =========================================================================
# Skip - wrong resource type
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-linux"
location: "eastus"
properties:
storageProfile:
osDisk:
osType: "Linux"
imageReference:
publisher: "Canonical"
offer: "UbuntuServer"
sku: "18.04-lts"
parameters:
dcrResourceId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Insights/dataCollectionRules/dcr1"
effect: "DeployIfNotExists"
scopeToSupportedImages: true
listOfLinuxImageIdToInclude: []
resourceType: "Microsoft.Insights/dataCollectionRules"
want_undefined: true

View File

@@ -0,0 +1,130 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Compute/DoubleEncryptionRequired_Deny
# Real Azure Policy: "Managed disks should be double encrypted with both
# platform-managed and customer-managed keys"
# Features: allOf, field (type + alias), equals, notEquals, parameters() with
# defaultValue and allowedValues, parameterized effect
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Managed disks should be double encrypted",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Deny", "Disabled"],
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/diskEncryptionSets"
},
{
"field": "Microsoft.Compute/diskEncryptionSets/encryptionType",
"notEquals": "EncryptionAtRestWithPlatformAndCustomerKeys"
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Audit (default effect) — wrong encryption type
# =========================================================================
- note: audit_single_key_encryption
resource:
type: "Microsoft.Compute/diskEncryptionSets"
name: "myDES"
location: "eastus"
properties:
encryptionType: "EncryptionAtRestWithCustomerKey"
want_effect: "Audit"
# =========================================================================
# No effect — correct double encryption
# =========================================================================
- note: pass_double_encryption
resource:
type: "Microsoft.Compute/diskEncryptionSets"
name: "myDES"
location: "eastus"
properties:
encryptionType: "EncryptionAtRestWithPlatformAndCustomerKeys"
want_undefined: true
# =========================================================================
# No effect — wrong resource type
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "myVM"
location: "eastus"
properties:
hardwareProfile:
vmSize: "Standard_D2s_v3"
want_undefined: true
# =========================================================================
# Deny — explicit effect parameter override
# =========================================================================
- note: deny_with_explicit_effect
resource:
type: "Microsoft.Compute/diskEncryptionSets"
name: "myDES"
location: "westus"
properties:
encryptionType: "EncryptionAtRestWithCustomerKey"
parameters:
effect: "Deny"
want_effect: "Deny"
# =========================================================================
# Audit — platform-only encryption (not double)
# =========================================================================
- note: audit_platform_only_encryption
resource:
type: "Microsoft.Compute/diskEncryptionSets"
name: "platformDES"
location: "eastus"
properties:
encryptionType: "EncryptionAtRestWithPlatformKey"
want_effect: "Audit"
# =========================================================================
# No effect — encryption type missing (field is undefined/null)
# notEquals with null LHS: Azure Policy treats missing field as null,
# and null notEquals "string" is true → should fire
# =========================================================================
- note: audit_missing_encryption_type
resource:
type: "Microsoft.Compute/diskEncryptionSets"
name: "noPropDES"
location: "eastus"
properties: {}
want_effect: "Audit"

View File

@@ -0,0 +1,247 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Managed Identity/FIC_LimitToAzureKubernetesIssuer
# Real Azure Policy: "Managed Identity Federated Credentials from Azure
# Kubernetes should be from trusted sources"
# Source: regolator/policyDefinitions/Managed Identity/FIC_LimitToAzureKubernetesIssuer.json
#
# Features exercised:
# - Value count (count over parameter arrays)
# - Complex nested if/split/length value expressions to parse issuer URL
# - Double negation: not { anyOf [...] }
# - Child resource type (sub-resource)
# - `like` operator with wildcard pattern
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Preview]: Managed Identity Federated Credentials from Azure Kubernetes should be from trusted sources",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"allowedTenants": {
"type": "Array",
"metadata": {
"displayName": "Allowed tenants",
"description": "The list of allowed Azure AD tenant ID's of AKS OIDC issuers. Empty to allow all tenants."
}
},
"allowedLocations": {
"type": "Array",
"defaultValue": [],
"metadata": {
"displayName": "Allowed locations",
"description": "The list of allowed locations for AKS OIDC issuers. Empty to allow any location."
}
},
"allowedClusterExceptions": {
"type": "Array",
"defaultValue": [],
"metadata": {
"displayName": "Allowed Exception Clusters",
"description": "The list of specific cluster ids that will be exceptions to the location and tenant rules."
}
},
"effect": {
"type": "String",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Disabled", "Deny"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
},
{
"allOf": [
{
"value": "[if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')),3),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')[2],'')]",
"like": "*.oic.prod-aks.azure.com"
},
{
"not": {
"anyOf": [
{
"allOf": [
{
"anyOf": [
{
"count": {
"value": "[parameters('allowedLocations')]"
},
"equals": 0
},
{
"value": "[if(greaterOrEquals(length(split(if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')),3),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')[2],''), '.')),1),split(if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')),3),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')[2],''), '.')[0],'')]",
"in": "[parameters('allowedLocations')]"
}
]
},
{
"anyOf": [
{
"count": {
"value": "[parameters('allowedTenants')]"
},
"equals": 0
},
{
"value": "[if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')),4),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')[3],'')]",
"in": "[parameters('allowedTenants')]"
}
]
}
]
},
{
"value": "[if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')),5),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer'),'/')[4],'')]",
"in": "[parameters('allowedClusterExceptions')]"
}
]
}
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Audit — untrusted AKS issuer (wrong tenant AND wrong location)
# =========================================================================
- note: audit_untrusted_tenant_and_location
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "aks-fic"
properties:
issuer: "https://eastus.oic.prod-aks.azure.com/bad-tenant-id/some-cluster-id"
subject: "system:serviceaccount:default:workload-identity-sa"
parameters:
allowedTenants: ["good-tenant-id"]
allowedLocations: ["westus"]
allowedClusterExceptions: []
want_effect: "Audit"
# =========================================================================
# Audit — correct location but wrong tenant
# =========================================================================
- note: audit_wrong_tenant_correct_location
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "aks-fic"
properties:
issuer: "https://eastus.oic.prod-aks.azure.com/bad-tenant-id/some-cluster-id"
subject: "system:serviceaccount:default:workload-identity-sa"
parameters:
allowedTenants: ["good-tenant-id"]
allowedLocations: ["eastus"]
allowedClusterExceptions: []
want_effect: "Audit"
# =========================================================================
# Pass — allowed tenant and allowed location
# =========================================================================
- note: pass_allowed_tenant_and_location
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "aks-fic"
properties:
issuer: "https://eastus.oic.prod-aks.azure.com/good-tenant-id/some-cluster-id"
subject: "system:serviceaccount:default:workload-identity-sa"
parameters:
allowedTenants: ["good-tenant-id", "other-tenant-id"]
allowedLocations: ["eastus", "westus"]
allowedClusterExceptions: []
want_undefined: true
# =========================================================================
# Pass — allowed tenant, empty allowedLocations (any location allowed)
# =========================================================================
- note: pass_allowed_tenant_any_location
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "aks-fic"
properties:
issuer: "https://westeurope.oic.prod-aks.azure.com/good-tenant-id/some-cluster-id"
subject: "system:serviceaccount:default:workload-identity-sa"
parameters:
allowedTenants: ["good-tenant-id"]
allowedLocations: []
allowedClusterExceptions: []
want_undefined: true
# =========================================================================
# Pass — empty allowedTenants and empty allowedLocations (allow all)
# =========================================================================
- note: pass_empty_tenants_and_locations_allows_all
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "aks-fic"
properties:
issuer: "https://australiaeast.oic.prod-aks.azure.com/any-tenant/any-cluster"
subject: "system:serviceaccount:kube-system:my-sa"
parameters:
allowedTenants: []
allowedLocations: []
allowedClusterExceptions: []
want_undefined: true
# =========================================================================
# Pass — cluster ID is in the exceptions list (bypasses tenant/location)
# =========================================================================
- note: pass_cluster_in_exceptions
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "aks-fic"
properties:
issuer: "https://eastus.oic.prod-aks.azure.com/untrusted-tenant/special-cluster-id"
subject: "system:serviceaccount:default:workload-identity-sa"
parameters:
allowedTenants: ["other-tenant"]
allowedLocations: ["westus"]
allowedClusterExceptions: ["special-cluster-id"]
want_undefined: true
# =========================================================================
# Pass — non-AKS issuer (GitHub Actions OIDC)
# =========================================================================
- note: pass_non_aks_issuer
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "github-fic"
properties:
issuer: "https://token.actions.githubusercontent.com"
subject: "repo:myorg/myrepo:ref:refs/heads/main"
parameters:
allowedTenants: ["some-tenant"]
want_undefined: true
# =========================================================================
# Skip — wrong resource type entirely
# =========================================================================
- note: skip_wrong_resource_type
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities"
name: "my-identity"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,184 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Managed Identity/FIC_LimitToGitHubIssuer
# Real Azure Policy: "Managed Identity Federated Credentials from GitHub
# should be from trusted repository owners"
# Source: regolator/policyDefinitions/Managed Identity/FIC_LimitToGitHubIssuer.json
#
# Features exercised:
# - Value count (count over parameter array)
# - Complex nested if/split/length value expressions to parse subject field
# - Double negation: not { anyOf [...] }
# - Child resource type (sub-resource)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Preview]: Managed Identity Federated Credentials from GitHub should be from trusted repository owners",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"allowedRepoOwners": {
"type": "Array",
"metadata": {
"displayName": "Allowed Repo Owners"
}
},
"allowedRepoExceptions": {
"type": "Array",
"defaultValue": [],
"metadata": {
"displayName": "Allowed Repo Exceptions"
}
},
"effect": {
"type": "String",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Disabled", "Deny"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
},
{
"allOf": [
{
"field": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/issuer",
"equals": "https://token.actions.githubusercontent.com"
},
{
"not": {
"anyOf": [
{
"allOf": [
{
"anyOf": [
{
"count": {
"value": "[parameters('allowedRepoOwners')]"
},
"equals": 0
},
{
"value": "[if(greaterOrEquals(length(split(if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/subject'),':')),2),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/subject'),':')[1],''), '/')),2),split(if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/subject'),':')),2),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/subject'),':')[1],''), '/')[0],'')]",
"in": "[parameters('allowedRepoOwners')]"
}
]
}
]
},
{
"value": "[if(greaterOrEquals(length(split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/subject'),':')),2),split(field('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/subject'),':')[1],'')]",
"in": "[parameters('allowedRepoExceptions')]"
}
]
}
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Audit — untrusted repo owner (not in allowedRepoOwners)
# =========================================================================
- note: audit_untrusted_repo_owner
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "github-fic"
properties:
issuer: "https://token.actions.githubusercontent.com"
subject: "repo:evil-org/malicious-repo:ref:refs/heads/main"
parameters:
allowedRepoOwners: ["trusted-org", "another-org"]
allowedRepoExceptions: []
want_effect: "Audit"
# =========================================================================
# Pass — repo owner is in the allowed list
# =========================================================================
- note: pass_allowed_repo_owner
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "github-fic"
properties:
issuer: "https://token.actions.githubusercontent.com"
subject: "repo:trusted-org/my-repo:ref:refs/heads/main"
parameters:
allowedRepoOwners: ["trusted-org", "another-org"]
allowedRepoExceptions: []
want_undefined: true
# =========================================================================
# Pass — repo is in exceptions list (even if owner not allowed)
# =========================================================================
- note: pass_repo_in_exceptions
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "github-fic"
properties:
issuer: "https://token.actions.githubusercontent.com"
subject: "repo:random-org/special-repo:ref:refs/heads/main"
parameters:
allowedRepoOwners: ["trusted-org"]
allowedRepoExceptions: ["random-org/special-repo"]
want_undefined: true
# =========================================================================
# Pass — empty allowedRepoOwners means allow all
# =========================================================================
- note: pass_empty_owners_allows_all
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "github-fic"
properties:
issuer: "https://token.actions.githubusercontent.com"
subject: "repo:any-org/any-repo:ref:refs/heads/main"
parameters:
allowedRepoOwners: []
allowedRepoExceptions: []
want_undefined: true
# =========================================================================
# Pass — not a GitHub issuer (different OIDC provider)
# =========================================================================
- note: pass_non_github_issuer
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
name: "aks-fic"
properties:
issuer: "https://oidc.prod-aks.azure.com/00000000-0000-0000-0000-000000000000"
subject: "system:serviceaccount:default:workload-identity-sa"
parameters:
allowedRepoOwners: ["trusted-org"]
want_undefined: true
# =========================================================================
# Skip — wrong resource type
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.ManagedIdentity/userAssignedIdentities"
name: "my-identity"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,183 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: App Service/FunctionApp_AuditHTTP_Modify
# Real Azure Policy: "Configure Function apps to only be accessible over HTTPS"
# Source: regolator/policyDefinitions/App Service/FunctionApp_AuditHTTP_Modify.json
#
# Features exercised:
# - kind contains / notContains string operators
# - exists "false" — field doesn't exist or is null
# - Modify with greaterOrEquals(requestContext().apiVersion,...) condition
# - conflictEffect: audit
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure Function apps to only be accessible over HTTPS",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Modify",
"allowedValues": ["Modify", "Disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Web/sites"
},
{
"field": "kind",
"contains": "functionapp"
},
{
"field": "kind",
"notContains": "workflowapp"
},
{
"anyOf": [
{
"field": "Microsoft.Web/sites/httpsOnly",
"exists": "false"
},
{
"field": "Microsoft.Web/sites/httpsOnly",
"equals": "false"
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/de139f84-1756-47ae-9be6-808fbbe84772"
],
"conflictEffect": "audit",
"operations": [
{
"condition": "[greaterOrEquals(requestContext().apiVersion, '2019-08-01')]",
"operation": "addOrReplace",
"field": "Microsoft.Web/sites/httpsOnly",
"value": true
}
]
}
}
}
}
}
cases:
# =========================================================================
# Function app with httpsOnly missing → Modify
# =========================================================================
- note: modify_functionapp_httpsonly_missing
resource:
type: "Microsoft.Web/sites"
kind: "functionapp"
name: "func-no-https"
properties: {}
api_version: "2022-03-01"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/microsoft.authorization/roleDefinitions/de139f84-1756-47ae-9be6-808fbbe84772"
operations:
- condition: "[greaterOrEquals(requestContext().apiVersion, '2019-08-01')]"
operation: "addOrReplace"
field: "Microsoft.Web/sites/httpsOnly"
value: true
# =========================================================================
# Function app with httpsOnly = false → Modify
# =========================================================================
- note: modify_functionapp_httpsonly_false
resource:
type: "Microsoft.Web/sites"
kind: "functionapp,linux"
name: "func-linux-no-https"
properties:
httpsOnly: false
api_version: "2020-06-01"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/microsoft.authorization/roleDefinitions/de139f84-1756-47ae-9be6-808fbbe84772"
operations:
- condition: "[greaterOrEquals(requestContext().apiVersion, '2019-08-01')]"
operation: "addOrReplace"
field: "Microsoft.Web/sites/httpsOnly"
value: true
# =========================================================================
# Function app with httpsOnly = true → pass (condition not met)
# =========================================================================
- note: pass_functionapp_httpsonly_true
resource:
type: "Microsoft.Web/sites"
kind: "functionapp"
name: "func-https"
properties:
httpsOnly: true
api_version: "2022-03-01"
want_undefined: true
# =========================================================================
# Workflow app (Logic App) — notContains "workflowapp" fails → pass
# =========================================================================
- note: pass_workflowapp_excluded
resource:
type: "Microsoft.Web/sites"
kind: "functionapp,workflowapp"
name: "logic-app"
properties: {}
api_version: "2022-03-01"
want_undefined: true
# =========================================================================
# Web app (not function app) — contains "functionapp" fails → pass
# =========================================================================
- note: pass_webapp_not_functionapp
resource:
type: "Microsoft.Web/sites"
kind: "app"
name: "web-app"
properties:
httpsOnly: false
api_version: "2022-03-01"
want_undefined: true
# =========================================================================
# Old API version → operation condition not met, no operations emitted
# =========================================================================
- note: modify_old_api_no_operations
resource:
type: "Microsoft.Web/sites"
kind: "functionapp"
name: "func-old-api"
properties: {}
api_version: "2018-02-01"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/microsoft.authorization/roleDefinitions/de139f84-1756-47ae-9be6-808fbbe84772"
operations:
- condition: "[greaterOrEquals(requestContext().apiVersion, '2019-08-01')]"
operation: "addOrReplace"
field: "Microsoft.Web/sites/httpsOnly"
value: true

View File

@@ -0,0 +1,836 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Guest Configuration/AddUserIdentity_Prerequisite
# Real Azure Policy: "[Preview]: Add user-assigned managed identity to enable Guest Configuration assignments on virtual machines"
# Source: regolator/policyDefinitions/Guest Configuration/AddUserIdentity_Prerequisite.json
#
# Features exercised:
# - Self-referential DeployIfNotExists (details.type matches resource type)
# - identity.type / identity.userAssignedIdentities existenceCondition
# - containsKey with concat(subscription().subscriptionId, field('location'))
# - Deep allOf/anyOf nesting for OS image publisher matching (Windows + Linux)
# - requestContext().apiVersion guard (>= 2018-10-01)
# - deploymentScope: subscription
# - subscription-level ARM deployment template
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Preview]: Add user-assigned managed identity to enable Guest Configuration assignments on virtual machines",
"mode": "Indexed",
"policyType": "BuiltIn",
"description": "This policy adds a user-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration. A user-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. For more information on Guest Configuration, visit https://aka.ms/gcpol.",
"metadata": {
"category": "Guest Configuration",
"version": "2.1.0-preview",
"preview": true
},
"version": "2.1.0-preview",
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Policy Effect",
"description": "The effect determines what happens when the policy rule is evaluated to match."
},
"allowedValues": [
"AuditIfNotExists",
"DeployIfNotExists",
"Disabled"
],
"defaultValue": "DeployIfNotExists"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"anyOf": [
{
"anyOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"in": [
"esri",
"incredibuild",
"MicrosoftDynamicsAX",
"MicrosoftSharepoint",
"MicrosoftVisualStudio",
"MicrosoftWindowsDesktop",
"MicrosoftWindowsServerHPCPack"
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftWindowsServer"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "2008*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftSQLServer"
},
{
"field": "Microsoft.Compute/imageOffer",
"notLike": "SQL2008*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-dsvm"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "dsvm-win*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-ads"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"standard-data-science-vm",
"windows-data-science-vm"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "batch"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "rendering-windows2016"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "center-for-internet-security-inc"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "cis-windows-server-201*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "pivotal"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "bosh-windows-server*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "cloud-infrastructure-services"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "ad*"
}
]
},
{
"allOf": [
{
"anyOf": [
{
"field": "Microsoft.Compute/virtualMachines/osProfile.windowsConfiguration",
"exists": "true"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType",
"like": "Windows*"
}
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSKU",
"exists": "false"
},
{
"allOf": [
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "2008*"
},
{
"field": "Microsoft.Compute/imageOffer",
"notLike": "SQL2008*"
}
]
}
]
}
]
}
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"in": [
"microsoft-aks",
"qubole-inc",
"datastax",
"couchbase",
"scalegrid",
"checkpoint",
"paloaltonetworks",
"debian",
"credativ"
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "OpenLogic"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Oracle"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "RedHat"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "center-for-internet-security-inc"
},
{
"field": "Microsoft.Compute/imageOffer",
"notLike": "cis-win*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Suse"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "11*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Canonical"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "12*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-dsvm"
},
{
"field": "Microsoft.Compute/imageOffer",
"notLike": "dsvm-win*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "cloudera"
},
{
"field": "Microsoft.Compute/imageSKU",
"notLike": "6*"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-ads"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "linux*"
}
]
},
{
"allOf": [
{
"anyOf": [
{
"field": "Microsoft.Compute/virtualMachines/osProfile.linuxConfiguration",
"exists": "true"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType",
"like": "Linux*"
}
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"exists": "false"
},
{
"field": "Microsoft.Compute/imagePublisher",
"notIn": [
"OpenLogic",
"RedHat",
"credativ",
"Suse",
"Canonical",
"microsoft-dsvm",
"cloudera",
"microsoft-ads",
"center-for-internet-security-inc",
"Oracle",
"AzureDatabricks",
"azureopenshift"
]
}
]
}
]
}
]
}
]
},
{
"value": "[requestContext().apiVersion]",
"greaterOrEquals": "2018-10-01"
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Compute/virtualMachines",
"name": "[field('name')]",
"evaluationDelay": "AfterProvisioning",
"deploymentScope": "subscription",
"existenceCondition": {
"allOf": [
{
"field": "identity.type",
"contains": "UserAssigned"
},
{
"field": "identity.userAssignedIdentities",
"containsKey": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/Built-In-Identity-RG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Built-In-Identity-', field('location'))]"
}
]
},
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
"/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9"
],
"deployment": {
"location": "eastus",
"properties": {
"mode": "incremental",
"parameters": {
"bringYourOwnUserAssignedManagedIdentity": {
"value": false
},
"location": {
"value": "[field('location')]"
},
"uaName": {
"value": "Built-In-Identity"
},
"identityResourceGroup": {
"value": "Built-In-Identity-RG"
},
"vmName": {
"value": "[field('name')]"
},
"vmResourceGroup": {
"value": "[resourceGroup().name]"
},
"resourceId": {
"value": "[field('id')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.1",
"parameters": {
"bringYourOwnUserAssignedManagedIdentity": {
"type": "bool"
},
"location": {
"type": "string"
},
"uaName": {
"type": "string"
},
"identityResourceGroup": {
"type": "string"
},
"vmName": {
"type": "string"
},
"vmResourceGroup": {
"type": "string"
},
"resourceId": {
"type": "string"
}
},
"variables": {
"uaNameWithLocation": "[concat(parameters('uaName'),'-', parameters('location'))]",
"precreatedUaId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', trim(parameters('identityResourceGroup')), '/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', trim(parameters('uaName')))]",
"autocreatedUaId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', trim(parameters('identityResourceGroup')), '/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', trim(parameters('uaName')), '-', parameters('location'))]",
"deployUALockName": "[concat('deployUALock-', uniqueString(deployment().name))]",
"deployUAName": "[concat('deployUA-', uniqueString(deployment().name))]",
"deployGetResourceProperties": "[concat('deployGetResourceProperties-', uniqueString(deployment().name))]",
"deployAssignUAName": "[concat('deployAssignUA-', uniqueString(deployment().name))]"
},
"resources": [
{
"condition": "[not(parameters('bringYourOwnUserAssignedManagedIdentity'))]",
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2020-06-01",
"name": "[parameters('identityResourceGroup')]",
"location": "eastus"
},
{
"condition": "[parameters('bringYourOwnUserAssignedManagedIdentity')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-06-01",
"name": "[variables('deployUALockName')]",
"resourceGroup": "[parameters('identityResourceGroup')]",
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"parameters": {
"uaName": {
"value": "[parameters('uaName')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"uaName": {
"type": "string"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Authorization/locks",
"apiVersion": "2016-09-01",
"name": "[concat('CanNotDeleteLock-', parameters('uaName'))]",
"scope": "[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('uaName'))]",
"properties": {
"level": "CanNotDelete",
"notes": "Please do not delete this User-Assigned Identity since extensions enabled by Azure Policy are relying on their existence."
}
}
]
}
}
},
{
"condition": "[not(parameters('bringYourOwnUserAssignedManagedIdentity'))]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-06-01",
"name": "[variables('deployUAName')]",
"resourceGroup": "[parameters('identityResourceGroup')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups', parameters('identityResourceGroup'))]"
],
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"parameters": {
"uaName": {
"value": "[variables('uaNameWithLocation')]"
},
"location": {
"value": "[parameters('location')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"uaName": {
"type": "string"
},
"location": {
"type": "string"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"name": "[parameters('uaName')]",
"apiVersion": "2018-11-30",
"location": "[parameters('location')]"
},
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities/providers/locks",
"apiVersion": "2016-09-01",
"name": "[concat(parameters('uaName'), '/Microsoft.Authorization/', 'CanNotDeleteLock-', parameters('uaName'))]",
"dependsOn": [
"[parameters('uaName')]"
],
"properties": {
"level": "CanNotDelete",
"notes": "Please do not delete this User-Assigned Identity since extensions enabled by Azure Policy are relying on their existence."
}
}
]
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-06-01",
"name": "[variables('deployGetResourceProperties')]",
"location": "eastus",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups', parameters('identityResourceGroup'))]",
"[variables('deployUAName')]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [],
"outputs": {
"resource": {
"type": "object",
"value": "[reference(parameters('resourceId'), '2019-07-01', 'Full')]"
}
}
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-06-01",
"name": "[concat(variables('deployAssignUAName'))]",
"resourceGroup": "[parameters('vmResourceGroup')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups', parameters('identityResourceGroup'))]",
"[variables('deployUAName')]",
"[variables('deployGetResourceProperties')]"
],
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"parameters": {
"uaId": {
"value": "[if(parameters('bringYourOwnUserAssignedManagedIdentity'), variables('precreatedUaId'), variables('autocreatedUaId'))]"
},
"vmName": {
"value": "[parameters('vmName')]"
},
"location": {
"value": "[parameters('location')]"
},
"identityType": {
"value": "[if(contains(reference(variables('deployGetResourceProperties')).outputs.resource.value, 'identity'), reference(variables('deployGetResourceProperties')).outputs.resource.value.identity.type, '')]"
},
"userAssignedIdentities": {
"value": "[if(and(contains(reference(variables('deployGetResourceProperties')).outputs.resource.value, 'identity'), contains(reference(variables('deployGetResourceProperties')).outputs.resource.value.identity, 'userAssignedIdentities')), reference(variables('deployGetResourceProperties')).outputs.resource.value.identity.userAssignedIdentities, createObject())]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"uaId": {
"type": "string"
},
"vmName": {
"type": "string"
},
"location": {
"type": "string"
},
"identityType": {
"type": "string"
},
"userAssignedIdentities": {
"type": "object"
}
},
"variables": {
"identityTypeValue": "[if(contains(parameters('identityType'), 'SystemAssigned'), 'SystemAssigned,UserAssigned', 'UserAssigned')]",
"userAssignedIdentitiesValue": "[union(parameters('userAssignedIdentities'), createObject(parameters('uaId'), createObject()))]"
},
"resources": [
{
"apiVersion": "2019-07-01",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('vmName')]",
"location": "[parameters('location')]",
"identity": {
"type": "[variables('identityTypeValue')]",
"userAssignedIdentities": "[variables('userAssignedIdentitiesValue')]"
}
}
]
}
}
}
]
}
}
}
}
}
}
},
"versions": [
"2.1.0-PREVIEW",
"2.0.1-PREVIEW"
]
}
cases:
# =========================================================================
# DINE — Windows VM (MicrosoftWindowsServer), no user-assigned identity
# → existenceCondition fails → DeployIfNotExists
# =========================================================================
- note: dine_windows_vm_no_identity
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-win-noidentity"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm-win-noidentity"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
osDisk:
osType: "Windows"
osProfile:
windowsConfiguration: {}
request_context:
apiVersion: "2024-01-01"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Compute/virtualMachines"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Pass — Windows VM with proper user-assigned identity in existence result
# → existenceCondition passes → compliant
# =========================================================================
- note: pass_windows_vm_with_identity
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-win-identified"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm-win-identified"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
osDisk:
osType: "Windows"
osProfile:
windowsConfiguration: {}
request_context:
apiVersion: "2024-01-01"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Compute/virtualMachines"
response:
identity:
type: "UserAssigned"
userAssignedIdentities:
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/Built-In-Identity-RG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/Built-In-Identity-eastus": {}
want_undefined: true
# =========================================================================
# DINE — Linux VM (Canonical publisher), no user-assigned identity
# → existenceCondition fails → DeployIfNotExists
# =========================================================================
- note: dine_linux_vm_no_identity
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-linux-noidentity"
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm-linux-noidentity"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "Canonical"
offer: "UbuntuServer"
sku: "18.04-LTS"
osDisk:
osType: "Linux"
osProfile:
linuxConfiguration: {}
request_context:
apiVersion: "2024-01-01"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Compute/virtualMachines"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Pass — Wrong resource type (not a VM) → if condition fails
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "storageacct1"
properties: {}
want_undefined: true
# =========================================================================
# Pass — Linux VM with microsoft-ads publisher and non-matching offer
# → microsoft-ads specific conditions require offer like "linux*"
# or in ["standard-data-science-vm","windows-data-science-vm"]
# → Linux catch-all excludes microsoft-ads (it's in the notIn list)
# → Windows catch-all fails (no windowsConfiguration, osType=Linux)
# → if condition fails
# =========================================================================
- note: pass_excluded_publisher
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-ads-excluded"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "microsoft-ads"
offer: "some-random-offer"
sku: "some-sku"
osDisk:
osType: "Linux"
osProfile:
linuxConfiguration: {}
request_context:
apiVersion: "2024-01-01"
want_undefined: true
# =========================================================================
# Pass — VM without osProfile and no matching publisher
# → Windows catch-all: no windowsConfiguration, no Windows osType
# → Linux catch-all: no linuxConfiguration, no Linux osType
# → No specific publisher match
# → if condition fails
# =========================================================================
- note: pass_no_os_config
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-no-os"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "unknown-publisher"
offer: "unknown-offer"
sku: "unknown-sku"
request_context:
apiVersion: "2024-01-01"
want_undefined: true

View File

@@ -0,0 +1,127 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Key Vault/FirewallEnabled_Audit
# Features: nested count + current() + ipRangeContains + parameterized effect/defaults
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Azure Key Vault should have firewall enabled",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Audit", "Deny", "Disabled"],
"defaultValue": "Audit"
},
"restrictIPAddresses": {
"type": "String",
"defaultValue": "No",
"allowedValues": ["Yes", "No"]
},
"allowedIPAddresses": {
"type": "Array",
"defaultValue": []
}
},
"policyRule": {
"if": {
"allOf": [
{"field": "type", "equals": "Microsoft.KeyVault/vaults"},
{"field": "Microsoft.KeyVault/vaults/createMode", "notEquals": "recover"},
{
"anyOf": [
{
"field": "Microsoft.KeyVault/vaults/networkAcls.defaultAction",
"notEquals": "Deny"
},
{
"allOf": [
{"value": "[parameters('restrictIPAddresses')]", "equals": "Yes"},
{
"anyOf": [
{
"allOf": [
{
"count": {
"value": "[parameters('allowedIPAddresses')]",
"name": "allowedIPAddresses"
},
"notEquals": 0
},
{
"not": {
"count": {
"field": "Microsoft.KeyVault/vaults/networkAcls.ipRules[*]",
"where": {
"count": {
"value": "[parameters('allowedIPAddresses')]",
"name": "allowedIpAddress",
"where": {
"value": "[ipRangeContains(current('allowedIpAddress'), current('Microsoft.KeyVault/vaults/networkAcls.ipRules[*].value'))]",
"equals": true
}
},
"greater": 0
}
},
"equals": "[length(field('Microsoft.KeyVault/vaults/networkAcls.ipRules[*]'))]"
}
}
]
}
]
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
- note: audit_when_default_action_allow
resource:
type: "Microsoft.KeyVault/vaults"
name: "kv-open"
properties:
networkAcls:
defaultAction: "Allow"
ipRules: []
want_effect: "Audit"
- note: pass_when_default_action_deny_and_no_restriction_mode
resource:
type: "Microsoft.KeyVault/vaults"
name: "kv-deny"
properties:
networkAcls:
defaultAction: "Deny"
ipRules: []
want_undefined: true
- note: audit_when_restricted_allowed_ips_do_not_cover_all_rules
resource:
type: "Microsoft.KeyVault/vaults"
name: "kv-partial"
properties:
networkAcls:
defaultAction: "Deny"
ipRules:
- value: "10.0.0.5"
- value: "192.168.1.5"
parameters:
restrictIPAddresses: "Yes"
allowedIPAddresses: ["10.0.0.0/24"]
effect: "Audit"
want_effect: "Audit"

View File

@@ -0,0 +1,326 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Compute/ManagedDiskEncryptionSetsAllowed_Deny
# Real Azure Policy: "Managed disks should use a specific set of disk encryption sets for the customer-managed key encryption"
# Features: anyOf, allOf nesting, field (type + alias), exists, notIn, in,
# length(), count, not, multiple resource types
# (VM, VMSS, disks, images, galleries/images/versions)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Managed disks should use a specific set of disk encryption sets for the customer-managed key encryption",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Requiring a specific set of disk encryption sets to be used with managed disks give you control over the keys used for encryption at rest. You are able to select the allowed encrypted sets and all others are rejected when attached to a disk. Learn more at https://aka.ms/disks-cmk.",
"metadata": {
"category": "Compute",
"version": "2.0.0"
},
"version": "2.0.0",
"parameters": {
"allowedEncryptionSets": {
"type": "Array",
"metadata": {
"displayName": "Allowed disk encryption set",
"description": "The list of allowed disk encryption sets for managed disks.",
"strongType": "Microsoft.Compute/diskEncryptionSets"
}
},
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": [
"Audit",
"Deny",
"Disabled"
],
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
}
}
},
"policyRule": {
"if": {
"anyOf": [
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/disks"
},
{
"field": "Microsoft.Compute/disks/managedBy",
"exists": "False"
},
{
"field": "Microsoft.Compute/disks/encryption.diskEncryptionSetId",
"notIn": "[parameters('allowedEncryptionSets')]"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.managedDisk.diskEncryptionSet.id",
"notIn": "[parameters('allowedEncryptionSets')]"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachineScaleSets"
},
{
"field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.storageProfile.osDisk.managedDisk.diskEncryptionSet.id",
"notIn": "[parameters('allowedEncryptionSets')]"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachineScaleSets"
},
{
"count": {
"field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.storageProfile.dataDisks[*]"
},
"greater": 0
},
{
"not": {
"field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.storageProfile.dataDisks[*].managedDisk.diskEncryptionSet.id",
"in": "[parameters('allowedEncryptionSets')]"
}
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/galleries/images/versions"
},
{
"not": {
"field": "Microsoft.Compute/galleries/images/versions/publishingProfile.targetRegions[*].encryption.osDiskImage.diskEncryptionSetId",
"in": "[parameters('allowedEncryptionSets')]"
}
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/galleries/images/versions"
},
{
"value": "[length(field('Microsoft.Compute/galleries/images/versions/storageProfile.dataDiskImages[*]'))]",
"greater": 0
},
{
"not": {
"field": "Microsoft.Compute/galleries/images/versions/publishingProfile.targetRegions[*].encryption.dataDiskImages[*].diskEncryptionSetId",
"in": "[parameters('allowedEncryptionSets')]"
}
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/images"
},
{
"field": "Microsoft.Compute/images/storageProfile.osDisk.diskEncryptionSet.id",
"notIn": "[parameters('allowedEncryptionSets')]"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/images"
},
{
"value": "[length(field('Microsoft.Compute/images/storageProfile.dataDisks[*]'))]",
"greater": 0
},
{
"field": "Microsoft.Compute/images/storageProfile.dataDisks[*].diskEncryptionSet.id",
"notIn": "[parameters('allowedEncryptionSets')]"
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
},
"versions": [
"2.0.0"
]
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/d461a302-a187-421a-89ac-84acdb4edc04",
"name": "d461a302-a187-421a-89ac-84acdb4edc04"
}
cases:
# =========================================================================
# 1. VM with OS disk DES in allowed list → pass
# =========================================================================
- note: pass_vm_osdisk_in_allowed
parameters:
effect: "Deny"
allowedEncryptionSets:
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des2"
resource:
type: "Microsoft.Compute/virtualMachines"
name: "test-vm"
properties:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
want_undefined: true
# =========================================================================
# 2. VM with OS disk DES NOT in allowed list → Deny
# =========================================================================
- note: deny_vm_osdisk_not_in_allowed
parameters:
effect: "Deny"
allowedEncryptionSets:
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des2"
resource:
type: "Microsoft.Compute/virtualMachines"
name: "test-vm-bad"
properties:
storageProfile:
osDisk:
managedDisk:
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des-other"
want_effect: "Deny"
# =========================================================================
# 3. Managed disk with allowed DES → pass
# =========================================================================
- note: pass_disk_in_allowed
parameters:
effect: "Deny"
allowedEncryptionSets:
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des2"
resource:
type: "Microsoft.Compute/disks"
name: "test-disk-allowed"
properties:
diskSizeGB: 128
encryption:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
type: "EncryptionAtRestWithCustomerKey"
want_undefined: true
# =========================================================================
# 4. Managed disk with disallowed DES → Deny
# =========================================================================
- note: deny_disk_not_in_allowed
parameters:
effect: "Deny"
allowedEncryptionSets:
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des2"
resource:
type: "Microsoft.Compute/disks"
name: "test-disk-bad"
properties:
diskSizeGB: 128
encryption:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des-other"
type: "EncryptionAtRestWithCustomerKey"
want_effect: "Deny"
# =========================================================================
# 5. Disk without managedBy (unmanaged) with disallowed DES → Deny
# (managedBy does not exist, so the disk clause fires)
# But if the DES is in the allowed list, it passes.
# Here we test: disk without managedBy but WITH managedBy present → pass
# (the disk clause requires managedBy exists=False)
# =========================================================================
- note: pass_disk_unmanaged
parameters:
effect: "Deny"
allowedEncryptionSets:
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
resource:
type: "Microsoft.Compute/disks"
name: "test-disk-managed-by-vm"
properties:
managedBy: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/myVM"
diskSizeGB: 128
encryption:
diskEncryptionSetId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des-other"
type: "EncryptionAtRestWithCustomerKey"
want_undefined: true
# =========================================================================
# 6. Wrong resource type → pass
# =========================================================================
- note: pass_wrong_type
parameters:
effect: "Deny"
allowedEncryptionSets:
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
resource:
type: "Microsoft.Storage/storageAccounts"
name: "myStorage"
properties: {}
want_undefined: true
# =========================================================================
# 7. Image with OS disk DES not in allowed list → Deny
# =========================================================================
- note: deny_image_osdisk_not_allowed
parameters:
effect: "Deny"
allowedEncryptionSets:
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des1"
- "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des2"
resource:
type: "Microsoft.Compute/images"
name: "test-image-bad"
properties:
storageProfile:
osDisk:
osType: "Linux"
osState: "Generalized"
diskEncryptionSet:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/diskEncryptionSets/des-other"
want_effect: "Deny"

View File

@@ -0,0 +1,182 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Monitoring DINE existenceCondition — field + count + nested count
# Reproduces the failure pattern from ServiceHealthSubscriptionLevelAlertRules_DINE
#
# Uses bare field names (no FQ alias prefix, no alias catalog) to test
# existence logic independent of alias resolution.
policy_definition: |
{
"properties": {
"displayName": "Test DINE existenceCondition",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "String",
"defaultValue": "DeployIfNotExists",
"allowedValues": ["DeployIfNotExists", "AuditIfNotExists", "Disabled"]
},
"enableAlertRule": {
"type": "String",
"defaultValue": "true",
"allowedValues": ["true", "false"]
},
"eventTypes": {
"type": "Array",
"defaultValue": ["Service Issues", "Planned Maintenance", "Health Advisories", "Security Advisories"]
},
"actionGroups": {
"type": "Array",
"defaultValue": []
},
"createNewActionGroup": {
"type": "String",
"defaultValue": "true",
"allowedValues": ["true", "false"]
},
"newActionGroupName": {
"type": "String",
"defaultValue": "ag-ServiceHealthAlertActionGroup"
},
"resourceGroupName": {
"type": "String",
"defaultValue": "rg-serviceHealthAlert"
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Resources/subscriptions"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Insights/ActivityLogAlerts",
"existenceCondition": {
"allOf": [
{
"field": "enabled",
"equals": "[parameters('enableAlertRule')]"
},
{
"count": {
"field": "condition.allOf[*]",
"where": {
"allOf": [
{
"field": "condition.allOf[*].field",
"equals": "category"
},
{
"field": "condition.allOf[*].equals",
"equals": "ServiceHealth"
}
]
}
},
"greaterOrEquals": 1
},
{
"count": {
"field": "condition.allOf[*].anyOf[*]",
"where": {
"field": "condition.allOf[*].anyOf[*].field",
"equals": "properties.incidentType"
}
},
"equals": "[if(contains(parameters('eventTypes'), 'Health Advisories'), add(length(parameters('eventTypes')), 2), length(parameters('eventTypes')))]"
},
{
"count": {
"field": "actions.actionGroups[*]"
},
"equals": "[add(length(parameters('actionGroups')), if(equals(parameters('createNewActionGroup'), 'true'), 1, 0))]"
}
]
},
"existenceScope": "resourceGroup",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
]
}
}
}
}
}
cases:
# =========================================================================
# Related resource matches all conditions → compliant (Undefined)
# =========================================================================
- note: compliant_all_conditions
resource:
type: "Microsoft.Resources/subscriptions"
id: "/subscriptions/00000000-0000-0000-0000-000000000000"
parameters:
effect: "AuditIfNotExists"
host_await:
- response:
enabled: "true"
scopes:
- "/subscriptions/00000000-0000-0000-0000-000000000000"
condition:
allof:
- field: "category"
equals: "ServiceHealth"
- anyof:
- field: "properties.incidentType"
equals: "Incident"
- field: "properties.incidentType"
equals: "Maintenance"
- field: "properties.incidentType"
equals: "Informational"
- field: "properties.incidentType"
equals: "ActionRequired"
- field: "properties.incidentType"
equals: "Security"
- field: "properties.incidentType"
equals: "Retirement"
actions:
actiongroups:
- actiongroupid: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-serviceHealthAlert/providers/Microsoft.Insights/actionGroups/ag-ServiceHealthAlertActionGroup"
want_undefined: true
# =========================================================================
# Related resource not found → effect fires
# =========================================================================
- note: no_related_resource
resource:
type: "Microsoft.Resources/subscriptions"
id: "/subscriptions/00000000-0000-0000-0000-000000000000"
parameters:
effect: "AuditIfNotExists"
host_await:
- response: null
want_effect: "AuditIfNotExists"
# =========================================================================
# Related resource found but enabled is false → effect fires
# =========================================================================
- note: enabled_false
resource:
type: "Microsoft.Resources/subscriptions"
id: "/subscriptions/00000000-0000-0000-0000-000000000000"
parameters:
effect: "AuditIfNotExists"
host_await:
- response:
enabled: "false"
condition:
allof:
- field: "category"
equals: "ServiceHealth"
- anyof:
- field: "properties.incidentType"
equals: "Incident"
actions:
actiongroups:
- actiongroupid: "something"
want_effect: "AuditIfNotExists"

View File

@@ -0,0 +1,138 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Network/NetworkPublicIPNic_Deny
# Real Azure Policy: "Network interfaces should not have public IPs"
# Source: regolator/policyDefinitions/Network/NetworkPublicIPNic_Deny.json
#
# Features exercised:
# - Double negation pattern: not { field notLike "*" }
# - Wildcard array alias: ipconfigurations[*].publicIpAddress.id
# - No parameters (hardcoded deny effect)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Network interfaces should not have public IPs",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkInterfaces"
},
{
"not": {
"field": "Microsoft.Network/networkInterfaces/ipconfigurations[*].publicIpAddress.id",
"notLike": "*"
}
}
]
},
"then": {
"effect": "deny"
}
}
}
}
cases:
# =========================================================================
# NIC with public IP → deny
# =========================================================================
- note: deny_single_ip_config_with_public_ip
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-public"
properties:
ipConfigurations:
- properties:
privateIPAddress: "10.0.0.4"
publicIpAddress:
id: "/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/pip1"
want_effect: "deny"
- note: deny_multiple_ip_configs_all_public
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-multi-public"
properties:
ipConfigurations:
- properties:
privateIPAddress: "10.0.0.4"
publicIpAddress:
id: "/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/pip1"
- properties:
privateIPAddress: "10.0.0.5"
publicIpAddress:
id: "/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/pip2"
want_effect: "deny"
- note: deny_one_of_many_has_public_ip
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-mixed"
properties:
ipConfigurations:
- properties:
privateIPAddress: "10.0.0.4"
- properties:
privateIPAddress: "10.0.0.5"
publicIpAddress:
id: "/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/pip1"
want_effect: "deny"
# =========================================================================
# NIC without public IP → pass
# =========================================================================
- note: pass_no_public_ip
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-private"
properties:
ipConfigurations:
- properties:
privateIPAddress: "10.0.0.4"
want_undefined: true
- note: pass_multiple_configs_no_public_ip
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-multi-private"
properties:
ipConfigurations:
- properties:
privateIPAddress: "10.0.0.4"
- properties:
privateIPAddress: "10.0.0.5"
want_undefined: true
- note: pass_empty_ip_configs
resource:
type: "Microsoft.Network/networkInterfaces"
name: "nic-empty"
properties:
ipConfigurations: []
want_undefined: true
# =========================================================================
# Wrong resource type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "not-a-nic"
properties:
ipConfigurations:
- properties:
publicIpAddress:
id: "some-id"
want_undefined: true

View File

@@ -0,0 +1,370 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Network/NetworkSecurityGroup_RDPAccess_Audit
# Real Azure Policy: "[Deprecated]: RDP access from the Internet should be blocked"
# Features: and(), not(), lessOrEquals(), greaterOrEquals(), implicit allOf on [*]
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Deprecated]: RDP access from the Internet should be blocked",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkSecurityGroups/securityRules"
},
{
"allOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/access",
"equals": "Allow"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/direction",
"equals": "Inbound"
},
{
"anyOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange",
"equals": "*"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange",
"equals": "3389"
},
{
"value": "[if(and(not(empty(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'))), contains(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'),'-')), and(lessOrEquals(int(first(split(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'), '-'))),3389),greaterOrEquals(int(last(split(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'), '-'))),3389)), 'false')]",
"equals": "true"
},
{
"count": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]",
"where": {
"value": "[if(and(not(empty(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')))), contains(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')),'-')), and(lessOrEquals(int(first(split(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')), '-'))),3389),greaterOrEquals(int(last(split(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')), '-'))),3389)) , 'false')]",
"equals": "true"
}
},
"greater": 0
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]",
"notEquals": "*"
}
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]",
"notEquals": "3389"
}
}
]
},
{
"anyOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix",
"equals": "*"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix",
"equals": "Internet"
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefixes[*]",
"notEquals": "*"
}
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefixes[*]",
"notEquals": "Internet"
}
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Exact port 3389 match
# =========================================================================
- note: audit_exact_port_3389_from_internet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-rdp"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3389"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: audit_exact_port_3389_from_wildcard
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-rdp-any"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3389"
sourceAddressPrefix: "*"
want_effect: "Audit"
# =========================================================================
# Wildcard port (*)
# =========================================================================
- note: audit_wildcard_port_from_internet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-all"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "*"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
# =========================================================================
# Port range containing 3389
# =========================================================================
- note: audit_port_range_includes_3389
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-rdp-range"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3380-3390"
sourceAddressPrefix: "*"
want_effect: "Audit"
- note: audit_port_range_exact_3389_to_3389
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "exactly-3389"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3389-3389"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: audit_port_range_1_to_4000
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "low-ports"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "1-4000"
sourceAddressPrefix: "*"
want_effect: "Audit"
# =========================================================================
# Port range NOT containing 3389
# =========================================================================
- note: pass_port_range_excludes_3389
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "http-only"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "80-443"
destinationPortRanges: []
sourceAddressPrefix: "Internet"
sourceAddressPrefixes: []
want_undefined: true
- note: pass_port_3390_only
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "port-3390"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3390"
destinationPortRanges: []
sourceAddressPrefix: "*"
sourceAddressPrefixes: []
want_undefined: true
# =========================================================================
# destinationPortRanges[*] array — double negation pattern
# =========================================================================
- note: audit_port_ranges_array_contains_3389
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "multi-port-rdp"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "80"
- "3389"
- "443"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: audit_port_ranges_array_contains_wildcard
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "multi-port-wildcard"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "*"
sourceAddressPrefix: "*"
want_effect: "Audit"
- note: audit_port_ranges_array_with_range_containing_3389
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "multi-port-range"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "80-443"
- "3380-3390"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: pass_port_ranges_array_no_3389
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "non-rdp-ports"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "80"
- "443"
- "8080"
sourceAddressPrefix: "Internet"
want_undefined: true
# =========================================================================
# Source address variations
# =========================================================================
- note: audit_source_prefixes_array_wildcard
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "src-wild-array"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3389"
sourceAddressPrefixes:
- "*"
want_effect: "Audit"
- note: audit_source_prefixes_array_internet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "src-inet-array"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3389"
sourceAddressPrefixes:
- "Internet"
want_effect: "Audit"
- note: pass_source_is_private_subnet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "private-rdp"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3389"
destinationPortRanges: []
sourceAddressPrefix: "10.0.0.0/8"
sourceAddressPrefixes: []
want_undefined: true
- note: pass_source_prefixes_all_private
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "private-array"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "3389"
destinationPortRanges: []
sourceAddressPrefixes:
- "10.0.0.0/8"
- "172.16.0.0/12"
want_undefined: true
# =========================================================================
# Non-matching access / direction
# =========================================================================
- note: pass_deny_rule
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "deny-rdp"
properties:
access: "Deny"
direction: "Inbound"
destinationPortRange: "3389"
sourceAddressPrefix: "*"
want_undefined: true
- note: pass_outbound_rule
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "outbound-rdp"
properties:
access: "Allow"
direction: "Outbound"
destinationPortRange: "3389"
sourceAddressPrefix: "*"
want_undefined: true
# =========================================================================
# Wrong resource type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-nsg"
properties:
access: "Allow"
want_undefined: true

View File

@@ -0,0 +1,379 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Network/NetworkSecurityGroup_SSHAccess_Audit
# Real Azure Policy: "[Deprecated]: SSH access from the Internet should be blocked"
# Source: regolator/policyDefinitions/Network/NetworkSecurityGroup_SSHAccess_Audit.json
#
# Features exercised:
# - Deeply nested template expressions: if(and(not(empty(...)), contains(...)))
# - Arithmetic in templates: int(), split(), first(), last()
# - Port range parsing: lessOrEquals/greaterOrEquals on split results
# - count with where clause + template expression
# - Double negation pattern: not { field notEquals "x" }
# - Parameterized effect with defaultValue
# - Multiple anyOf branches (destination port + source address)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "[Deprecated]: SSH access from the Internet should be blocked",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkSecurityGroups/securityRules"
},
{
"allOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/access",
"equals": "Allow"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/direction",
"equals": "Inbound"
},
{
"anyOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange",
"equals": "*"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange",
"equals": "22"
},
{
"value": "[if(and(not(empty(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'))), contains(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'),'-')), and(lessOrEquals(int(first(split(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'), '-'))),22),greaterOrEquals(int(last(split(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'), '-'))),22)), 'false')]",
"equals": "true"
},
{
"count": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]",
"where": {
"value": "[if(and(not(empty(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')))), contains(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')),'-')), and(lessOrEquals(int(first(split(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')), '-'))),22),greaterOrEquals(int(last(split(first(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]')), '-'))),22)) , 'false')]",
"equals": "true"
}
},
"greater": 0
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]",
"notEquals": "*"
}
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]",
"notEquals": "22"
}
}
]
},
{
"anyOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix",
"equals": "*"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix",
"equals": "Internet"
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefixes[*]",
"notEquals": "*"
}
},
{
"not": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefixes[*]",
"notEquals": "Internet"
}
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Exact port 22 match
# =========================================================================
- note: audit_exact_port_22_from_internet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-ssh"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "22"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: audit_exact_port_22_from_wildcard
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-ssh-any"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "22"
sourceAddressPrefix: "*"
want_effect: "Audit"
# =========================================================================
# Wildcard port (*)
# =========================================================================
- note: audit_wildcard_port_from_internet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-all"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "*"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
# =========================================================================
# Port range containing 22
# =========================================================================
- note: audit_port_range_includes_22
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-ssh-range"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "20-25"
sourceAddressPrefix: "*"
want_effect: "Audit"
- note: audit_port_range_exact_22_to_22
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "exactly-22"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "22-22"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: audit_port_range_1_to_1024
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "low-ports"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "1-1024"
sourceAddressPrefix: "*"
want_effect: "Audit"
# =========================================================================
# Port range NOT containing 22
# =========================================================================
- note: pass_port_range_excludes_22
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "http-only"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "80-443"
destinationPortRanges: []
sourceAddressPrefix: "Internet"
sourceAddressPrefixes: []
want_undefined: true
- note: pass_port_23_only
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "port-23"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "23"
destinationPortRanges: []
sourceAddressPrefix: "*"
sourceAddressPrefixes: []
want_undefined: true
# =========================================================================
# destinationPortRanges[*] array — double negation pattern
# =========================================================================
- note: audit_port_ranges_array_contains_22
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "multi-port-ssh"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "80"
- "22"
- "443"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: audit_port_ranges_array_contains_wildcard
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "multi-port-wildcard"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "*"
sourceAddressPrefix: "*"
want_effect: "Audit"
- note: audit_port_ranges_array_with_range_containing_22
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "multi-port-range"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "80-443"
- "10-30"
sourceAddressPrefix: "Internet"
want_effect: "Audit"
- note: pass_port_ranges_array_no_22
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "non-ssh-ports"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRanges:
- "80"
- "443"
- "8080"
sourceAddressPrefix: "Internet"
want_undefined: true
# =========================================================================
# Source address variations
# =========================================================================
- note: audit_source_prefixes_array_wildcard
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "src-wild-array"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "22"
sourceAddressPrefixes:
- "*"
want_effect: "Audit"
- note: audit_source_prefixes_array_internet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "src-inet-array"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "22"
sourceAddressPrefixes:
- "Internet"
want_effect: "Audit"
- note: pass_source_is_private_subnet
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "private-ssh"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "22"
destinationPortRanges: []
sourceAddressPrefix: "10.0.0.0/8"
sourceAddressPrefixes: []
want_undefined: true
- note: pass_source_prefixes_all_private
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "private-array"
properties:
access: "Allow"
direction: "Inbound"
destinationPortRange: "22"
destinationPortRanges: []
sourceAddressPrefixes:
- "10.0.0.0/8"
- "172.16.0.0/12"
want_undefined: true
# =========================================================================
# Non-matching access / direction
# =========================================================================
- note: pass_deny_rule
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "deny-ssh"
properties:
access: "Deny"
direction: "Inbound"
destinationPortRange: "22"
sourceAddressPrefix: "*"
want_undefined: true
- note: pass_outbound_rule
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "outbound-ssh"
properties:
access: "Allow"
direction: "Outbound"
destinationPortRange: "22"
sourceAddressPrefix: "*"
want_undefined: true
# =========================================================================
# Wrong resource type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-nsg"
properties:
access: "Allow"
want_undefined: true

View File

@@ -0,0 +1,121 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: PostgreSQL/FlexibleServers_EnablePgAudit_AINE
# Real Azure Policy: "Auditing with PgAudit should be enabled for PostgreSQL
# flexible servers"
# Source: regolator/policyDefinitions/PostgreSQL/FlexibleServers_EnablePgAudit_AINE.json
#
# Features exercised:
# - AuditIfNotExists with simple existenceCondition (notEquals)
# - Sub-resource type: Microsoft.DBforPostgreSQL/flexibleServers/configurations
# - host_await for cross-resource lookup
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Auditing with PgAudit should be enabled for PostgreSQL flexible servers",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "AuditIfNotExists",
"allowedValues": ["AuditIfNotExists", "Disabled"]
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.DBforPostgreSQL/flexibleServers"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.DBforPostgreSQL/flexibleServers/configurations",
"name": "pgaudit.log",
"existenceCondition": {
"field": "Microsoft.DBforPostgreSQL/flexibleServers/configurations/value",
"notEquals": "none"
}
}
}
}
}
}
cases:
# =========================================================================
# Related resource not found → AuditIfNotExists
# =========================================================================
- note: aine_config_not_found
resource:
type: "Microsoft.DBforPostgreSQL/flexibleServers"
name: "pg-no-config"
properties: {}
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.DBforPostgreSQL/flexibleServers/configurations"
name: "pgaudit.log"
response: null
want_effect: "AuditIfNotExists"
# =========================================================================
# pgaudit.log value is "all" → compliant
# =========================================================================
- note: compliant_pgaudit_enabled
resource:
type: "Microsoft.DBforPostgreSQL/flexibleServers"
name: "pg-audit-on"
properties: {}
host_await:
- response:
properties:
value: "all"
want_undefined: true
# =========================================================================
# pgaudit.log value is "none" → non-compliant (notEquals "none" fails)
# =========================================================================
- note: aine_pgaudit_none
resource:
type: "Microsoft.DBforPostgreSQL/flexibleServers"
name: "pg-audit-off"
properties: {}
host_await:
- response:
properties:
value: "none"
want_effect: "AuditIfNotExists"
# =========================================================================
# pgaudit.log value has specific categories → compliant
# =========================================================================
- note: compliant_pgaudit_specific
resource:
type: "Microsoft.DBforPostgreSQL/flexibleServers"
name: "pg-audit-specific"
properties: {}
host_await:
- response:
properties:
value: "read,write,ddl"
want_undefined: true
# =========================================================================
# Wrong type → pass
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Sql/servers"
name: "not-pg"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,240 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Portal/SharedDashboardInlineContent_Deny
# Real Azure Policy: "Shared dashboards should not have markdown tiles with inline content"
# Source: regolator/policyDefinitions/Portal/SharedDashboardInlineContent_Deny.json
#
# Features exercised:
# - Doubly-nested wildcard array: lenses[*].parts[*]
# - requestContext().apiVersion with greaterOrEquals version comparison
# - count with allOf+anyOf where clause
# - Very long alias names (Extension-HubsExtension-PartType-MarkdownPart...)
# - exists "false" inside count where
# - anyOf at top level selects old-API OR inline-content branches
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Shared dashboards should not have markdown tiles with inline content",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Deny", "Disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Portal/dashboards"
},
{
"anyof": [
{
"not": {
"value": "[requestContext().apiVersion]",
"greaterOrEquals": "2020-09-01-alpha"
}
},
{
"count": {
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*]",
"where": {
"allOf": [
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.type",
"equals": "Extension/HubsExtension/PartType/MarkdownPart"
},
{
"anyOf": [
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.Extension-HubsExtension-PartType-MarkdownPart.settings.content.settings.markdownUri",
"exists": "false"
},
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.Extension-HubsExtension-PartType-MarkdownPart.settings.content.settings.markdownSource",
"exists": "false"
},
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.Extension-HubsExtension-PartType-MarkdownPart.settings.content.settings.markdownSource",
"equals": "1"
}
]
}
]
}
},
"greater": 0
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Old API version (< 2020-09-01-alpha) → always audit
# =========================================================================
- note: audit_old_api_version
resource:
type: "Microsoft.Portal/dashboards"
name: "dash-old-api"
properties:
lenses: []
api_version: "2019-01-01-preview"
want_effect: "Audit"
# =========================================================================
# New API, markdown part with inline content (markdownSource = "1") → audit
# =========================================================================
- note: audit_markdown_inline_content
resource:
type: "Microsoft.Portal/dashboards"
name: "dash-inline"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownUri: "https://example.com/content.md"
markdownSource: "1"
api_version: "2022-12-01-preview"
want_effect: "Audit"
# =========================================================================
# New API, markdown part missing markdownUri → audit
# =========================================================================
- note: audit_markdown_missing_uri
resource:
type: "Microsoft.Portal/dashboards"
name: "dash-no-uri"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownSource: "2"
api_version: "2022-12-01-preview"
want_effect: "Audit"
# =========================================================================
# New API, markdown part missing markdownSource → audit
# =========================================================================
- note: audit_markdown_missing_source
resource:
type: "Microsoft.Portal/dashboards"
name: "dash-no-source"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownUri: "https://example.com/content.md"
api_version: "2022-12-01-preview"
want_effect: "Audit"
# =========================================================================
# New API, markdown part with external source (markdownSource != "1") → pass
# =========================================================================
- note: pass_markdown_external_source
resource:
type: "Microsoft.Portal/dashboards"
name: "dash-external"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownUri: "https://example.com/content.md"
markdownSource: "2"
api_version: "2022-12-01-preview"
want_undefined: true
# =========================================================================
# New API, non-markdown parts only → pass
# =========================================================================
- note: pass_no_markdown_parts
resource:
type: "Microsoft.Portal/dashboards"
name: "dash-charts"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MonitorChartPart"
- metadata:
type: "Extension/HubsExtension/PartType/VideoPart"
api_version: "2022-12-01-preview"
want_undefined: true
# =========================================================================
# New API, multiple lenses with mixed parts → audit if any inline
# =========================================================================
- note: audit_multi_lens_one_inline
resource:
type: "Microsoft.Portal/dashboards"
name: "dash-multi"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MonitorChartPart"
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownSource: "1"
markdownUri: "https://example.com/a.md"
api_version: "2022-12-01-preview"
want_effect: "Audit"
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "not-dashboard"
properties: {}
api_version: "2019-01-01"
want_undefined: true

View File

@@ -0,0 +1,116 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Service Bus/AuditDiagnosticLog_Audit
# Features: AuditIfNotExists with inline existenceCondition evaluation,
# including count-with-where and ARM template expression padLeft().
#
# NOTE: Without an alias catalog, fully-qualified field paths like
# "Microsoft.Insights/diagnosticSettings/logs[*]..." resolve as raw
# object keys. The test response structure mirrors this resolution.
policy_definition: |
{
"properties": {
"displayName": "Resource logs in Service Bus should be enabled",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "AuditIfNotExists",
"allowedValues": ["AuditIfNotExists", "Disabled"]
},
"requiredRetentionDays": {
"type": "String",
"defaultValue": "365"
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.ServiceBus/namespaces"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Insights/diagnosticSettings",
"existenceCondition": {
"count": {
"field": "Microsoft.Insights/diagnosticSettings/logs[*]",
"where": {
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.Insights/diagnosticSettings/logs[*].retentionPolicy.enabled",
"equals": "true"
},
{
"anyOf": [
{
"field": "Microsoft.Insights/diagnosticSettings/logs[*].retentionPolicy.days",
"equals": "0"
},
{
"value": "[padLeft(current('Microsoft.Insights/diagnosticSettings/logs[*].retentionPolicy.days'), 3, '0')]",
"greaterOrEquals": "[padLeft(parameters('requiredRetentionDays'), 3, '0')]"
}
]
}
]
}
]
}
},
"greaterOrEquals": 1
}
}
}
}
}
}
cases:
# Related resource not found → non-compliant
- note: non_compliant_resource_not_found
resource:
type: "Microsoft.ServiceBus/namespaces"
name: "sb-a"
properties: {}
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Insights/diagnosticSettings"
response: null
want_effect: "AuditIfNotExists"
# Related resource found with compliant diagnostic log → compliant
- note: compliant_resource_found_and_condition_passes
resource:
type: "Microsoft.ServiceBus/namespaces"
name: "sb-b"
properties: {}
host_await:
- response:
Microsoft:
"Insights/diagnosticSettings/logs":
- retentionPolicy:
enabled: "true"
days: "365"
want_undefined: true
# Related resource found but retention too short → non-compliant
- note: non_compliant_retention_too_short
resource:
type: "Microsoft.ServiceBus/namespaces"
name: "sb-c"
properties: {}
host_await:
- response:
Microsoft:
"Insights/diagnosticSettings/logs":
- retentionPolicy:
enabled: "true"
days: "10"
want_effect: "AuditIfNotExists"

View File

@@ -0,0 +1,204 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Portal/SharedDashboardInlineContent_Deny
# Real Azure Policy: "Shared dashboards should not have markdown tiles with inline content"
# Source: regolator/policyDefinitions/Portal/SharedDashboardInlineContent_Deny.json
#
# Features exercised:
# - Doubly-nested wildcard: lenses[*].parts[*]
# - Field count with where clause on deeply-nested metadata paths
# - requestContext().apiVersion guard with NOT (double negation pattern)
# - "anyof" (lowercase 'o') variant
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Shared dashboards should not have markdown tiles with inline content",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "Audit",
"allowedValues": ["Audit", "Deny", "Disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Portal/dashboards"
},
{
"anyof": [
{
"not": {
"value": "[requestContext().apiVersion]",
"greaterOrEquals": "2020-09-01-alpha"
}
},
{
"count": {
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*]",
"where": {
"allOf": [
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.type",
"equals": "Extension/HubsExtension/PartType/MarkdownPart"
},
{
"anyOf": [
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.Extension-HubsExtension-PartType-MarkdownPart.settings.content.settings.markdownUri",
"exists": "false"
},
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.Extension-HubsExtension-PartType-MarkdownPart.settings.content.settings.markdownSource",
"exists": "false"
},
{
"field": "Microsoft.Portal/dashboards/lenses[*].parts[*].metadata.Extension-HubsExtension-PartType-MarkdownPart.settings.content.settings.markdownSource",
"equals": "1"
}
]
}
]
}
},
"greater": 0
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Old API version → triggers (not greaterOrEquals "2020-09-01-alpha")
# =========================================================================
- note: audit_old_api_version
resource:
type: "Microsoft.Portal/dashboards"
name: "old-api-dashboard"
properties:
lenses: []
request_context:
apiVersion: "2019-01-01"
want_effect: "Audit"
# =========================================================================
# New API version, markdown part with inline content (no markdownUri)
# =========================================================================
- note: audit_inline_markdown_no_uri
resource:
type: "Microsoft.Portal/dashboards"
name: "inline-md"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownSource: "1"
request_context:
apiVersion: "2022-12-01"
want_effect: "Audit"
# =========================================================================
# New API version, markdown part with markdownUri set → compliant
# =========================================================================
- note: pass_markdown_with_uri
resource:
type: "Microsoft.Portal/dashboards"
name: "external-md"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownUri: "https://raw.githubusercontent.com/org/repo/main/README.md"
markdownSource: "url"
request_context:
apiVersion: "2022-12-01"
want_undefined: true
# =========================================================================
# Non-markdown part → compliant
# =========================================================================
- note: pass_non_markdown_part
resource:
type: "Microsoft.Portal/dashboards"
name: "chart-dashboard"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MonitorChartPart"
request_context:
apiVersion: "2022-12-01"
want_undefined: true
# =========================================================================
# Multiple lenses/parts, mixed: one inline, one external → triggers
# =========================================================================
- note: audit_mixed_parts_one_inline
resource:
type: "Microsoft.Portal/dashboards"
name: "mixed-dashboard"
properties:
lenses:
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MonitorChartPart"
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownSource: "1"
- parts:
- metadata:
type: "Extension/HubsExtension/PartType/MarkdownPart"
Extension-HubsExtension-PartType-MarkdownPart:
settings:
content:
settings:
markdownUri: "https://example.com/md.md"
markdownSource: "url"
request_context:
apiVersion: "2022-12-01"
want_effect: "Audit"
# =========================================================================
# Wrong type → skip
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "storage"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,183 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: SignalR/PublicNetworkAccessDisabled_Modify
# Real Azure Policy: "Modify Azure SignalR Service resources to disable public network access"
# Source: regolator/policyDefinitions/SignalR/PublicNetworkAccessDisabled_Modify.json
#
# Features exercised:
# - Multi-modify (3 operations, one conditional)
# - Conditional modify gated on requestContext().apiVersion
# - conflictEffect: Audit
# - Bare field count (no where clause)
# - exists false
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Modify Azure SignalR Service resources to disable public network access",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Modify", "Disabled"],
"defaultValue": "Modify"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.SignalRService/SignalR"
},
{
"anyOf": [
{
"field": "Microsoft.SignalRService/SignalR/networkACLs.defaultAction",
"equals": "Allow"
},
{
"field": "Microsoft.SignalRService/SignalR/networkACLs.publicNetwork.allow",
"exists": false
},
{
"count": {
"field": "Microsoft.SignalRService/SignalR/networkACLs.publicNetwork.allow[*]"
},
"greater": 0
}
]
},
{
"field": "Microsoft.SignalRService/SignalR/publicNetworkAccess",
"notEquals": "Disabled"
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"conflictEffect": "Audit",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/8cf5e20a-e4b2-4e9d-b3a1-5ceb692c2761"
],
"operations": [
{
"operation": "addOrReplace",
"field": "Microsoft.SignalRService/SignalR/networkACLs.defaultAction",
"value": "Deny"
},
{
"operation": "addOrReplace",
"field": "Microsoft.SignalRService/SignalR/networkACLs.publicNetwork.allow",
"value": []
},
{
"condition": "[greaterOrEquals(requestContext().apiVersion, '2021-06-01-preview')]",
"operation": "addOrReplace",
"field": "Microsoft.SignalRService/SignalR/publicNetworkAccess",
"value": "Disabled"
}
]
}
}
}
}
}
cases:
# =========================================================================
# Modify — default action is Allow
# =========================================================================
- note: modify_default_action_allow
resource:
type: "Microsoft.SignalRService/SignalR"
name: "signalr-open"
properties:
networkACLs:
defaultAction: "Allow"
publicNetwork:
allow:
- "ServerConnection"
publicNetworkAccess: "Enabled"
want_effect: "Modify"
# =========================================================================
# Modify — publicNetwork.allow does not exist
# =========================================================================
- note: modify_public_allow_not_exists
resource:
type: "Microsoft.SignalRService/SignalR"
name: "signalr-no-allow"
properties:
networkACLs:
defaultAction: "Deny"
publicNetworkAccess: "Enabled"
want_effect: "Modify"
# =========================================================================
# Modify — publicNetwork.allow has items (count > 0)
# =========================================================================
- note: modify_public_allow_has_items
resource:
type: "Microsoft.SignalRService/SignalR"
name: "signalr-with-allow"
properties:
networkACLs:
defaultAction: "Deny"
publicNetwork:
allow:
- "ClientConnection"
- "ServerConnection"
publicNetworkAccess: "Enabled"
want_effect: "Modify"
# =========================================================================
# Compliant — already disabled
# =========================================================================
- note: pass_already_disabled
resource:
type: "Microsoft.SignalRService/SignalR"
name: "signalr-locked"
properties:
networkACLs:
defaultAction: "Deny"
publicNetwork:
allow: []
publicNetworkAccess: "Disabled"
want_undefined: true
# =========================================================================
# Compliant — defaultAction=Deny, no allow field, already disabled
# =========================================================================
- note: pass_deny_no_allow_disabled
resource:
type: "Microsoft.SignalRService/SignalR"
name: "signalr-minimal"
properties:
networkACLs:
defaultAction: "Deny"
publicNetwork:
allow: []
publicNetworkAccess: "Disabled"
want_undefined: true
# =========================================================================
# Wrong type → skip
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.SignalRService/WebPubSub"
name: "webpubsub"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,183 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: SQL/SqlServerAuditing_ActionsAndGroups_Audit
# Real Azure Policy: "SQL Auditing settings should have Action-Groups
# configured to capture critical activities"
# Source: regolator/policyDefinitions/SQL/SqlServerAuditing_ActionsAndGroups_Audit.json
#
# Features exercised:
# - AuditIfNotExists with existenceCondition
# - Triple double-negation: not { field[*] notEquals X } — asserts X is
# present in the array (aka "all elements are not-not-equal to X")
# - Wildcard array alias: auditActionsAndGroups[*]
# - host_await for cross-resource lookup
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "SQL Auditing settings should have Action-Groups configured to capture critical activities",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "AuditIfNotExists",
"allowedValues": ["AuditIfNotExists", "Disabled"]
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Sql/servers"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Sql/servers/auditingSettings",
"name": "default",
"existenceCondition": {
"allOf": [
{
"not": {
"field": "Microsoft.Sql/servers/auditingSettings/auditActionsAndGroups[*]",
"notEquals": "SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP"
}
},
{
"not": {
"field": "Microsoft.Sql/servers/auditingSettings/auditActionsAndGroups[*]",
"notEquals": "FAILED_DATABASE_AUTHENTICATION_GROUP"
}
},
{
"not": {
"field": "Microsoft.Sql/servers/auditingSettings/auditActionsAndGroups[*]",
"notEquals": "BATCH_COMPLETED_GROUP"
}
}
]
}
}
}
}
}
}
cases:
# =========================================================================
# Related resource not found → AuditIfNotExists
# =========================================================================
- note: aine_no_related_resource
resource:
type: "Microsoft.Sql/servers"
name: "sql-no-audit"
properties: {}
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Sql/servers/auditingSettings"
name: "default"
response: null
want_effect: "AuditIfNotExists"
# =========================================================================
# All three groups present → compliant (undefined)
# =========================================================================
- note: compliant_all_three_groups
resource:
type: "Microsoft.Sql/servers"
name: "sql-complete"
properties: {}
host_await:
- response:
properties:
auditactionsandgroups:
- "SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP"
- "FAILED_DATABASE_AUTHENTICATION_GROUP"
- "BATCH_COMPLETED_GROUP"
want_undefined: true
# =========================================================================
# All three present among extras → still compliant
# =========================================================================
- note: compliant_extras_present
resource:
type: "Microsoft.Sql/servers"
name: "sql-extras"
properties: {}
host_await:
- response:
properties:
auditactionsandgroups:
- "SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP"
- "FAILED_DATABASE_AUTHENTICATION_GROUP"
- "BATCH_COMPLETED_GROUP"
- "APPLICATION_ROLE_CHANGE_PASSWORD_GROUP"
- "DATABASE_OBJECT_ACCESS_GROUP"
want_undefined: true
# =========================================================================
# Missing BATCH_COMPLETED_GROUP → non-compliant
# =========================================================================
- note: aine_missing_batch_completed
resource:
type: "Microsoft.Sql/servers"
name: "sql-missing-batch"
properties: {}
host_await:
- response:
properties:
auditactionsandgroups:
- "SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP"
- "FAILED_DATABASE_AUTHENTICATION_GROUP"
want_effect: "AuditIfNotExists"
# =========================================================================
# Missing SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP → non-compliant
# =========================================================================
- note: aine_missing_successful_auth
resource:
type: "Microsoft.Sql/servers"
name: "sql-missing-success"
properties: {}
host_await:
- response:
properties:
auditactionsandgroups:
- "FAILED_DATABASE_AUTHENTICATION_GROUP"
- "BATCH_COMPLETED_GROUP"
want_effect: "AuditIfNotExists"
# =========================================================================
# Empty array → all three missing → non-compliant
# =========================================================================
- note: aine_empty_groups
resource:
type: "Microsoft.Sql/servers"
name: "sql-empty-groups"
properties: {}
host_await:
- response:
properties:
auditactionsandgroups: []
want_effect: "AuditIfNotExists"
# =========================================================================
# Wrong type → pass (if-condition fails)
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-sql"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,104 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: SQL/SqlServerAuditing_Audit
# Features: AuditIfNotExists with inline existenceCondition evaluation.
# The host returns the related resource (or null if not found), and the
# compiler evaluates the existenceCondition against it.
#
# NOTE: Without an alias catalog, fully-qualified field paths like
# "Microsoft.Sql/auditingSettings.state" resolve as raw object keys
# ("Microsoft" → "Sql/auditingSettings" → "state"). The test response
# structure mirrors this resolution.
policy_definition: |
{
"properties": {
"displayName": "Auditing on SQL server should be enabled",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "string",
"defaultValue": "AuditIfNotExists",
"allowedValues": ["AuditIfNotExists", "Disabled"]
},
"setting": {
"type": "String",
"defaultValue": "enabled",
"allowedValues": ["enabled", "disabled"]
}
},
"policyRule": {
"if": {
"allOf": [
{"field": "type", "equals": "Microsoft.Sql/servers"},
{"field": "kind", "notContains": "analytics"}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Sql/servers/auditingSettings",
"name": "default",
"existenceCondition": {
"field": "Microsoft.Sql/auditingSettings.state",
"equals": "[parameters('setting')]"
}
}
}
}
}
}
cases:
# Related resource not found → non-compliant
- note: non_compliant_resource_not_found
resource:
type: "Microsoft.Sql/servers"
kind: "v12.0"
name: "sql-a"
properties: {}
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Sql/servers/auditingSettings"
name: "default"
response: null
want_effect: "AuditIfNotExists"
# Related resource found and existenceCondition matches → compliant
- note: compliant_resource_found_and_condition_passes
resource:
type: "Microsoft.Sql/servers"
kind: "v12.0"
name: "sql-b"
properties: {}
host_await:
- response:
Microsoft:
"Sql/auditingSettings":
state: "enabled"
want_undefined: true
# Related resource found but existenceCondition fails → non-compliant
- note: non_compliant_condition_fails
resource:
type: "Microsoft.Sql/servers"
kind: "v12.0"
name: "sql-c"
properties: {}
host_await:
- response:
Microsoft:
"Sql/auditingSettings":
state: "disabled"
want_effect: "AuditIfNotExists"
# Primary resource type doesn't match → if-condition false → compliant
- note: pass_when_type_not_matching
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg"
properties: {}
want_undefined: true

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: VirtualEnclaves/StorageNetworkAccessBypassOnly_Modify
# Real Azure Policy: "Configure Storage Accounts to restrict network access
# through network ACL bypass configuration only"
# Source: regolator/policyDefinitions/VirtualEnclaves/StorageNetworkAccessBypassOnly_Modify.json
#
# Features exercised:
# - Three plain field counts (ipRules[*], resourceAccessRules[*], virtualNetworkRules[*])
# - greaterOrEquals 1 count comparison
# - Modify with 4 addOrReplace operations (no condition)
# - parameterised bypass configuration
# - notEquals on field
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure Storage Accounts to restrict network access through network ACL bypass configuration only",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Modify", "Disabled"],
"defaultValue": "Modify"
},
"bypassConfiguration": {
"type": "String",
"allowedValues": [
"None",
"AzureServices",
"Logging",
"Metrics",
"Logging, Metrics",
"Logging, Metrics, AzureServices",
"Logging, AzureServices",
"Metrics, AzureServices"
],
"defaultValue": "AzureServices"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"anyOf": [
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.defaultAction",
"notEquals": "Deny"
},
{
"count": {
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*]"
},
"greaterOrEquals": 1
},
{
"count": {
"field": "Microsoft.Storage/storageAccounts/networkAcls.resourceAccessRules[*]"
},
"greaterOrEquals": 1
},
{
"count": {
"field": "Microsoft.Storage/storageAccounts/networkAcls.virtualNetworkRules[*]"
},
"greaterOrEquals": 1
},
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.bypass",
"notEquals": "[parameters('bypassConfiguration')]"
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"conflictEffect": "audit",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab"
],
"operations": [
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/networkAcls.defaultAction",
"value": "Deny"
},
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules",
"value": []
},
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/networkAcls.virtualNetworkRules",
"value": []
},
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/networkAcls.bypass",
"value": "[parameters('bypassConfiguration')]"
}
]
}
}
}
}
}
cases:
# =========================================================================
# Fully compliant — defaultAction=Deny, no rules, bypass matches
# =========================================================================
- note: pass_fully_compliant
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg-compliant"
properties:
networkAcls:
defaultAction: "Deny"
ipRules: []
resourceAccessRules: []
virtualNetworkRules: []
bypass: "AzureServices"
want_undefined: true
# =========================================================================
# defaultAction != Deny → Modify
# =========================================================================
- note: modify_default_action_allow
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg-allow"
properties:
networkAcls:
defaultAction: "Allow"
ipRules: []
resourceAccessRules: []
virtualNetworkRules: []
bypass: "AzureServices"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab"
operations:
- operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/networkAcls.defaultAction"
value: "Deny"
- operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/networkAcls.ipRules"
value: []
- operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/networkAcls.virtualNetworkRules"
value: []
- operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/networkAcls.bypass"
value: "AzureServices"
# =========================================================================
# Has IP rules → count >= 1 triggers Modify
# =========================================================================
- note: modify_has_ip_rules
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg-ip-rules"
properties:
networkAcls:
defaultAction: "Deny"
ipRules:
- value: "10.0.0.1"
action: "Allow"
resourceAccessRules: []
virtualNetworkRules: []
bypass: "AzureServices"
want_effect: "Modify"
# =========================================================================
# Has vnet rules → count >= 1 triggers Modify
# =========================================================================
- note: modify_has_vnet_rules
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg-vnet-rules"
properties:
networkAcls:
defaultAction: "Deny"
ipRules: []
resourceAccessRules: []
virtualNetworkRules:
- id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/subnet1"
bypass: "AzureServices"
want_effect: "Modify"
# =========================================================================
# bypass != parameter → Modify
# =========================================================================
- note: modify_bypass_mismatch
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg-bypass"
properties:
networkAcls:
defaultAction: "Deny"
ipRules: []
resourceAccessRules: []
virtualNetworkRules: []
bypass: "None"
parameters:
bypassConfiguration: "AzureServices"
want_effect: "Modify"
# =========================================================================
# Custom bypass param, bypass matches → pass
# =========================================================================
- note: pass_custom_bypass_matches
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg-custom-bypass"
properties:
networkAcls:
defaultAction: "Deny"
ipRules: []
resourceAccessRules: []
virtualNetworkRules: []
bypass: "Logging, Metrics"
parameters:
bypassConfiguration: "Logging, Metrics"
want_undefined: true

View File

@@ -0,0 +1,114 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Custom Storage IP allowlist
# Features: count.field + where(allOf) with action gate + notIn(parameters()) +
# parameter defaults from policy definition.
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Storage IP allowlist",
"policyType": "Custom",
"mode": "Indexed",
"description": "Only allow IP rules that match an approved allowlist.",
"metadata": {
"version": "1.0.0",
"category": "Network"
},
"version": "1.0.0",
"parameters": {
"allowedIps": {
"type": "Array",
"metadata": {
"displayName": "Allowed IPs",
"description": "IP addresses permitted in IP rules"
},
"defaultValue": ["10.0.0.0/24", "192.168.10.10"]
},
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
},
"allowedValues": ["deny", "audit", "disabled"],
"defaultValue": "deny"
}
},
"policyRule": {
"if": {
"count": {
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*]",
"where": {
"allOf": [
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*].action",
"equals": "Allow"
},
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*].value",
"notIn": "[parameters('allowedIps')]"
}
]
}
},
"greater": 0
},
"then": {
"effect": "[parameters('effect')]"
}
},
"versions": ["1.0.0"]
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/storage-ip-allowlist",
"name": "storage-ip-allowlist",
"type": "Microsoft.Authorization/policyDefinitions"
}
cases:
- note: provided_payload_allow1_does_not_match_action_filter
resource:
name: "storage-dev"
type: "Microsoft.Storage/storageAccounts"
location: "westus2"
properties:
networkAcls:
ipRules:
- value: "10.0.0.0/24"
action: "Allow1"
- value: "203.0.113.5"
action: "Allow1"
context: {}
parameters: {}
want_undefined: true
- note: deny_when_allow_action_and_ip_not_in_allowlist
resource:
name: "storage-dev"
type: "Microsoft.Storage/storageAccounts"
location: "westus2"
properties:
networkAcls:
ipRules:
- value: "10.0.0.0/24"
action: "Allow"
- value: "203.0.113.5"
action: "Allow"
want_effect: "deny"
- note: pass_when_all_allow_actions_are_in_allowlist
resource:
name: "storage-dev"
type: "Microsoft.Storage/storageAccounts"
location: "westus2"
properties:
networkAcls:
ipRules:
- value: "10.0.0.0/24"
action: "Allow"
- value: "192.168.10.10"
action: "Allow"
want_undefined: true

View File

@@ -0,0 +1,125 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Custom Storage IP allowlist policy
# Features: count.field + where(allOf) + notIn + parameterized effect/defaults
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Storage IP allowlist",
"policyType": "Custom",
"mode": "Indexed",
"description": "Only allow IP rules that match an approved allowlist.",
"metadata": {
"version": "1.0.0",
"category": "Network"
},
"version": "1.0.0",
"parameters": {
"allowedIps": {
"type": "Array",
"metadata": {
"displayName": "Allowed IPs",
"description": "IP addresses permitted in IP rules"
},
"defaultValue": ["10.0.0.0/24", "192.168.10.10"]
},
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
},
"allowedValues": ["deny", "audit", "disabled"],
"defaultValue": "deny"
}
},
"policyRule": {
"if": {
"count": {
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*]",
"where": {
"allOf": [
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*].action",
"equals": "Allow"
},
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*].value",
"notIn": "[parameters('allowedIps')]"
}
]
}
},
"greater": 0
},
"then": {
"effect": "[parameters('effect')]"
}
},
"versions": ["1.0.0"]
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/storage-ip-allowlist",
"name": "storage-ip-allowlist",
"type": "Microsoft.Authorization/policyDefinitions"
}
cases:
- note: pass_when_action_is_not_exact_allow
resource:
name: "storage-dev"
type: "Microsoft.Storage/storageAccounts"
location: "westus2"
properties:
networkAcls:
ipRules:
- value: "10.0.0.0/24"
action: "Allow1"
- value: "203.0.113.5"
action: "Allow1"
want_undefined: true
- note: deny_when_disallowed_ip_has_allow_action
resource:
name: "storage-dev"
type: "Microsoft.Storage/storageAccounts"
location: "westus2"
properties:
networkAcls:
ipRules:
- value: "10.0.0.0/24"
action: "Allow"
- value: "203.0.113.5"
action: "Allow"
want_effect: "deny"
- note: pass_when_all_allow_ips_are_in_allowlist
resource:
name: "storage-dev"
type: "Microsoft.Storage/storageAccounts"
location: "westus2"
properties:
networkAcls:
ipRules:
- value: "10.0.0.0/24"
action: "Allow"
- value: "192.168.10.10"
action: "Allow"
want_undefined: true
- note: audit_when_effect_parameter_is_overridden
resource:
name: "storage-dev"
type: "Microsoft.Storage/storageAccounts"
location: "westus2"
properties:
networkAcls:
ipRules:
- value: "203.0.113.5"
action: "Allow"
parameters:
effect: "audit"
want_effect: "audit"

View File

@@ -0,0 +1,158 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Storage/StorageAccountDisablePublicBlobAccess_Modify
# Real Azure Policy: "Configure your Storage account public access to be disallowed"
# Source: regolator/policyDefinitions/Storage/StorageAccountDisablePublicBlobAccess_Modify.json
#
# Features exercised:
# - requestContext().apiVersion less / greaterOrEquals comparisons
# - exists "true" combined with value condition in allOf
# - Modify with requestContext().apiVersion operation condition
# - conflictEffect: audit
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure your Storage account public access to be disallowed",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Modify", "Disabled"],
"defaultValue": "Modify"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"anyOf": [
{
"allOf": [
{
"value": "[requestContext().apiVersion]",
"less": "2019-04-01"
},
{
"field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess",
"exists": "true"
}
]
},
{
"field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess",
"equals": "true"
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"conflictEffect": "audit",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab"
],
"operations": [
{
"condition": "[greaterOrEquals(requestContext().apiVersion, '2019-04-01')]",
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/allowBlobPublicAccess",
"value": false
}
]
}
}
}
}
}
cases:
# =========================================================================
# allowBlobPublicAccess = true, modern API → Modify
# =========================================================================
- note: modify_public_blob_enabled_modern_api
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg1"
properties:
allowBlobPublicAccess: true
api_version: "2021-02-01"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab"
operations:
- condition: "[greaterOrEquals(requestContext().apiVersion, '2019-04-01')]"
operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/allowBlobPublicAccess"
value: false
# =========================================================================
# Old API version + field exists → triggers via the less branch
# (requestContext().apiVersion < "2019-04-01" AND field exists → Modify)
# =========================================================================
- note: modify_old_api_field_exists
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg2"
properties:
allowBlobPublicAccess: false
api_version: "2018-11-01"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab"
operations:
- condition: "[greaterOrEquals(requestContext().apiVersion, '2019-04-01')]"
operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/allowBlobPublicAccess"
value: false
# =========================================================================
# Old API version but field doesn't exist → pass
# =========================================================================
- note: pass_old_api_field_missing
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg3"
properties: {}
api_version: "2018-11-01"
want_undefined: true
# =========================================================================
# allowBlobPublicAccess = false, modern API → pass
# =========================================================================
- note: pass_public_blob_disabled
resource:
type: "Microsoft.Storage/storageAccounts"
name: "stg4"
properties:
allowBlobPublicAccess: false
api_version: "2021-02-01"
want_undefined: true
# =========================================================================
# Wrong resource type → pass
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm1"
properties: {}
api_version: "2021-03-01"
want_undefined: true

View File

@@ -0,0 +1,180 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Storage/StorageAccountOnlyVnetRulesEnabled_Audit
# Real Azure Policy: "Storage accounts should restrict network access using
# virtual network rules"
# Features: allOf, anyOf, field (type + alias), equals, notEquals, field count
# (array [*] without where), greaterOrEquals, parameters() with defaultValue
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Storage accounts should restrict network access using virtual network rules",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the audit policy"
},
"allowedValues": ["Audit", "Deny", "Disabled"],
"defaultValue": "Audit"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"anyOf": [
{
"field": "Microsoft.Storage/storageAccounts/networkAcls.defaultAction",
"notEquals": "Deny"
},
{
"count": {
"field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules[*]"
},
"greaterOrEquals": 1
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# Audit — default action is Allow (not Deny)
# =========================================================================
- note: audit_default_action_allow
resource:
type: "Microsoft.Storage/storageAccounts"
name: "openStorage"
location: "eastus"
properties:
networkAcls:
defaultAction: "Allow"
ipRules: []
want_effect: "Audit"
# =========================================================================
# Audit — default action is Deny but has IP rules
# =========================================================================
- note: audit_deny_with_ip_rules
resource:
type: "Microsoft.Storage/storageAccounts"
name: "restrictedStorage"
location: "eastus"
properties:
networkAcls:
defaultAction: "Deny"
ipRules:
- value: "10.0.0.0/24"
action: "Allow"
want_effect: "Audit"
# =========================================================================
# No effect — default action is Deny and no IP rules
# =========================================================================
- note: pass_deny_no_ip_rules
resource:
type: "Microsoft.Storage/storageAccounts"
name: "vnetOnlyStorage"
location: "eastus"
properties:
networkAcls:
defaultAction: "Deny"
ipRules: []
want_undefined: true
# =========================================================================
# Audit — both violations: default Allow AND has IP rules
# =========================================================================
- note: audit_allow_with_ip_rules
resource:
type: "Microsoft.Storage/storageAccounts"
name: "wideOpenStorage"
location: "westus"
properties:
networkAcls:
defaultAction: "Allow"
ipRules:
- value: "192.168.1.0/24"
action: "Allow"
- value: "10.0.0.1"
action: "Allow"
want_effect: "Audit"
# =========================================================================
# Audit — networkAcls missing entirely (defaultAction undefined → notEquals
# "Deny" is true for null/undefined)
# =========================================================================
- note: audit_no_network_acls
resource:
type: "Microsoft.Storage/storageAccounts"
name: "noAclStorage"
location: "eastus"
properties: {}
want_effect: "Audit"
# =========================================================================
# No effect — wrong resource type
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "myVM"
location: "eastus"
properties: {}
want_undefined: true
# =========================================================================
# Deny — explicit effect parameter override
# =========================================================================
- note: deny_with_explicit_effect
resource:
type: "Microsoft.Storage/storageAccounts"
name: "openStorage"
location: "eastus"
properties:
networkAcls:
defaultAction: "Allow"
ipRules: []
parameters:
effect: "Deny"
want_effect: "Deny"
# =========================================================================
# No effect — Deny action, ipRules key missing (count over undefined = 0)
# =========================================================================
- note: pass_deny_no_ip_rules_key
resource:
type: "Microsoft.Storage/storageAccounts"
name: "minimalStorage"
location: "eastus"
properties:
networkAcls:
defaultAction: "Deny"
want_undefined: true

View File

@@ -0,0 +1,428 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Stream Analytics/DataExfiltration_Audit
# Real Azure Policy: "Stream Analytics job should connect to trusted inputs
# and outputs"
# Source: regolator/policyDefinitions/Stream Analytics/DataExfiltration_Audit.json
#
# Features exercised:
# - anyOf tree (2 top-level branches for outputs and streamingjobs)
# - Multiple datasource type checks with notIn on sub-resource types
# - Count with where clause on wildcard array (storageAccounts[*].accountName)
# - notIn operator with parameterised Array
# - Long alias paths with dots and hyphens (e.g. datasource.Microsoft-Storage-Blob.storageAccounts[*])
# - exists "true" + notIn combined check
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Stream Analytics job should connect to trusted inputs and outputs",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Deny", "Disabled", "Audit"],
"defaultValue": "Audit"
},
"allowedEventHubNamespaces": {
"type": "Array",
"defaultValue": []
},
"allowedSQLServers": {
"type": "Array",
"defaultValue": []
},
"allowedStorageAccounts": {
"type": "Array",
"defaultValue": []
},
"allowedCosmosAccounts": {
"type": "Array",
"defaultValue": []
},
"allowedAzureFunctionAccounts": {
"type": "Array",
"defaultValue": []
},
"allowedIoTHubNamespaces": {
"type": "Array",
"defaultValue": []
},
"allowedMLWebServiceEndpoints": {
"type": "Array",
"defaultValue": []
}
},
"policyRule": {
"if": {
"anyOf": [
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.StreamAnalytics/streamingjobs/outputs"
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type",
"equals": "Microsoft.EventHub/EventHub"
},
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-ServiceBus-EventHub.serviceBusNamespace",
"notIn": "[parameters('allowedEventHubNamespaces')]"
}
]
},
{
"allOf": [
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type",
"equals": "Microsoft.Sql/Server/Database"
},
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Sql-Server-Database.server",
"notIn": "[parameters('allowedSQLServers')]"
}
]
},
{
"allOf": [
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type",
"equals": "Microsoft.Storage/Table"
},
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-Table.accountName",
"notIn": "[parameters('allowedStorageAccounts')]"
}
]
},
{
"allOf": [
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type",
"equals": "Microsoft.Storage/DocumentDB"
},
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-DocumentDB.accountId",
"notIn": "[parameters('allowedCosmosAccounts')]"
}
]
},
{
"allOf": [
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type",
"equals": "Microsoft.AzureFunction"
},
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-AzureFunction.functionAppName",
"notIn": "[parameters('allowedAzureFunctionAccounts')]"
}
]
},
{
"allOf": [
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type",
"equals": "Microsoft.Storage/Blob"
},
{
"count": {
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-Blob.storageAccounts[*]",
"where": {
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-Blob.storageAccounts[*].accountName",
"notIn": "[parameters('allowedStorageAccounts')]"
}
},
"greater": 0
}
]
},
{
"field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type",
"notIn": [
"Microsoft.EventHub/EventHub",
"Microsoft.Sql/Server/Database",
"Microsoft.Storage/Table",
"Microsoft.Storage/DocumentDB",
"Microsoft.AzureFunction",
"Microsoft.Storage/Blob"
]
}
]
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.StreamAnalytics/streamingjobs"
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.StreamAnalytics/streamingjobs/jobStorageAccount",
"exists": "true"
},
{
"field": "Microsoft.StreamAnalytics/streamingjobs/jobStorageAccount.accountName",
"notIn": "[parameters('allowedStorageAccounts')]"
}
]
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
cases:
# =========================================================================
# OUTPUT: EventHub output to allowed namespace → pass
# =========================================================================
- note: pass_output_eventhub_allowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output1"
properties:
datasource:
type: "Microsoft.EventHub/EventHub"
Microsoft-ServiceBus-EventHub:
serviceBusNamespace: "my-eh-namespace"
parameters:
allowedEventHubNamespaces:
- "my-eh-namespace"
want_undefined: true
# =========================================================================
# OUTPUT: EventHub output to disallowed namespace → Audit
# =========================================================================
- note: audit_output_eventhub_disallowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output2"
properties:
datasource:
type: "Microsoft.EventHub/EventHub"
Microsoft-ServiceBus-EventHub:
serviceBusNamespace: "rogue-namespace"
parameters:
allowedEventHubNamespaces:
- "trusted-namespace"
want_effect: "Audit"
# =========================================================================
# OUTPUT: SQL output to allowed server → pass
# =========================================================================
- note: pass_output_sql_allowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-sql"
properties:
datasource:
type: "Microsoft.Sql/Server/Database"
Microsoft-Sql-Server-Database:
server: "sql-server-approved"
parameters:
allowedSQLServers:
- "sql-server-approved"
want_undefined: true
# =========================================================================
# OUTPUT: Blob storage with disallowed account in storageAccounts[*] → Audit
# =========================================================================
- note: audit_output_blob_disallowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-blob"
properties:
datasource:
type: "Microsoft.Storage/Blob"
Microsoft-Storage-Blob:
storageAccounts:
- accountName: "rogue-storage"
- accountName: "trusted-storage"
parameters:
allowedStorageAccounts:
- "trusted-storage"
want_effect: "Audit"
# =========================================================================
# OUTPUT: Blob storage with all accounts allowed → pass
# =========================================================================
- note: pass_output_blob_all_allowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-blob-ok"
properties:
datasource:
type: "Microsoft.Storage/Blob"
Microsoft-Storage-Blob:
storageAccounts:
- accountName: "trusted-storage"
parameters:
allowedStorageAccounts:
- "trusted-storage"
want_undefined: true
# =========================================================================
# OUTPUT: SQL output to disallowed server → Audit
# =========================================================================
- note: audit_output_sql_disallowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-sql-bad"
properties:
datasource:
type: "Microsoft.Sql/Server/Database"
Microsoft-Sql-Server-Database:
server: "rogue-sql-server"
parameters:
allowedSQLServers:
- "trusted-sql-server"
want_effect: "Audit"
# =========================================================================
# OUTPUT: Table output to disallowed account → Audit
# =========================================================================
- note: audit_output_table_disallowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-table"
properties:
datasource:
type: "Microsoft.Storage/Table"
Microsoft-Storage-Table:
accountName: "rogue-storage"
parameters:
allowedStorageAccounts:
- "trusted-storage"
want_effect: "Audit"
# =========================================================================
# OUTPUT: CosmosDB output to disallowed account → Audit
# =========================================================================
- note: audit_output_cosmosdb_disallowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-cosmosdb"
properties:
datasource:
type: "Microsoft.Storage/DocumentDB"
Microsoft-Storage-DocumentDB:
accountId: "rogue-cosmos-account"
parameters:
allowedCosmosAccounts:
- "trusted-cosmos-account"
want_effect: "Audit"
# =========================================================================
# OUTPUT: AzureFunction output to disallowed function app → Audit
# =========================================================================
- note: audit_output_function_disallowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-function"
properties:
datasource:
type: "Microsoft.AzureFunction"
Microsoft-AzureFunction:
functionAppName: "rogue-function-app"
parameters:
allowedAzureFunctionAccounts:
- "trusted-function-app"
want_effect: "Audit"
# =========================================================================
# OUTPUT: Unknown datasource type → Audit (not in known list)
# =========================================================================
- note: audit_output_unknown_type
resource:
type: "Microsoft.StreamAnalytics/streamingjobs/outputs"
name: "output-unknown"
properties:
datasource:
type: "Microsoft.SomeNewService/SomeType"
want_effect: "Audit"
# =========================================================================
# STREAMINGJOB: jobStorageAccount with disallowed account → Audit
# =========================================================================
- note: audit_job_storage_disallowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs"
name: "job1"
properties:
jobStorageAccount:
accountName: "rogue-storage"
parameters:
allowedStorageAccounts:
- "trusted-storage"
want_effect: "Audit"
# =========================================================================
# STREAMINGJOB: jobStorageAccount with allowed account → pass
# =========================================================================
- note: pass_job_storage_allowed
resource:
type: "Microsoft.StreamAnalytics/streamingjobs"
name: "job2"
properties:
jobStorageAccount:
accountName: "trusted-storage"
parameters:
allowedStorageAccounts:
- "trusted-storage"
want_undefined: true
# =========================================================================
# STREAMINGJOB: no jobStorageAccount → pass (exists "true" fails)
# =========================================================================
- note: pass_job_no_storage
resource:
type: "Microsoft.StreamAnalytics/streamingjobs"
name: "job3"
properties: {}
want_undefined: true
# =========================================================================
# Wrong type entirely → pass
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm1"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,115 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Tags/ApplyTag_Append
# Real Azure Policy: "Append a tag and its value to resources"
# Source: regolator/policyDefinitions/Tags/ApplyTag_Append.json
#
# Features exercised:
# - Append effect with details array
# - concat() for dynamic tag field
# - exists operator ("false")
# - No type filter (applies to all resource types)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Append a tag and its value to resources",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"tagName": {
"type": "String"
},
"tagValue": {
"type": "String"
}
},
"policyRule": {
"if": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
},
"then": {
"effect": "append",
"details": [
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[parameters('tagValue')]"
}
]
}
}
}
}
cases:
# =========================================================================
# Tag missing → append
# =========================================================================
- note: append_tag_missing
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-no-env"
properties:
tags: {}
parameters:
tagName: "environment"
tagValue: "production"
want_effect: "append"
want_details:
- field: "[concat('tags[', parameters('tagName'), ']')]"
value: "production"
- note: append_no_tags_at_all
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-no-tags"
properties: {}
parameters:
tagName: "costCenter"
tagValue: "12345"
want_effect: "append"
- note: append_other_tags_exist
resource:
type: "Microsoft.Storage/storageAccounts"
name: "sa-partial-tags"
properties:
tags:
owner: "alice"
parameters:
tagName: "environment"
tagValue: "staging"
want_effect: "append"
# =========================================================================
# Tag already exists → pass
# =========================================================================
- note: pass_tag_already_exists
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-has-env"
properties:
tags:
environment: "dev"
parameters:
tagName: "environment"
tagValue: "production"
want_undefined: true
- note: pass_tag_matches_value
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-correct"
properties:
tags:
environment: "production"
parameters:
tagName: "environment"
tagValue: "production"
want_undefined: true

View File

@@ -0,0 +1,147 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Tags/InheritTag_AddOrReplace_Modify
# Real Azure Policy: "Inherit a tag from the resource group"
# Source: regolator/policyDefinitions/Tags/InheritTag_AddOrReplace_Modify.json
#
# Features exercised:
# - resourceGroup() template function
# - concat() to build dynamic tag field path: tags[<tagName>]
# - Parameter-derived field names
# - Modify effect with addOrReplace operation
# - value condition with resourceGroup().tags[parameters('tagName')]
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Inherit a tag from the resource group",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'environment'"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"notEquals": "[resourceGroup().tags[parameters('tagName')]]"
},
{
"value": "[resourceGroup().tags[parameters('tagName')]]",
"notEquals": ""
}
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[resourceGroup().tags[parameters('tagName')]]"
}
]
}
}
}
}
}
cases:
# =========================================================================
# Resource tag differs from resource group tag → modify
# =========================================================================
- note: modify_tag_differs
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-wrong-env"
properties:
tags:
environment: "dev"
parameters:
tagName: "environment"
context:
resourceGroup:
tags:
environment: "production"
want_effect: "modify"
- note: modify_tag_missing_on_resource
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-no-tag"
properties: {}
parameters:
tagName: "environment"
context:
resourceGroup:
tags:
environment: "production"
want_effect: "modify"
# =========================================================================
# Resource tag matches resource group tag → pass
# =========================================================================
- note: pass_tag_matches
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-correct-env"
properties:
tags:
environment: "production"
parameters:
tagName: "environment"
context:
resourceGroup:
tags:
environment: "production"
want_undefined: true
# =========================================================================
# Resource group tag is empty → pass (second condition fails)
# =========================================================================
- note: pass_rg_tag_empty
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-rg-empty"
properties:
tags:
environment: "dev"
parameters:
tagName: "environment"
context:
resourceGroup:
tags:
environment: ""
want_undefined: true
- note: pass_rg_tag_missing
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-rg-no-tag"
properties:
tags:
environment: "dev"
parameters:
tagName: "environment"
context:
resourceGroup:
tags: {}
want_undefined: true

View File

@@ -0,0 +1,861 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Backup/VirtualMachineBackup_DINE
# Real Azure Policy: "Configure backup on virtual machines without a given tag
# to an existing recovery services vault in the same location"
# Source: regolator/policyDefinitions/Backup/VirtualMachineBackup_DINE.json
#
# Features exercised:
# - DeployIfNotExists effect
# - concat('tags[', parameters('exclusionTagName'), ']') — dynamic tag field access
# - empty() function for Boolean branching
# - notEquals for image publisher exclusion (azureopenshift, AzureDatabricks)
# - notContains on resource id (databricks-rg-)
# - Large anyOf/allOf for image publisher/offer/SKU matching
# - host_await for cross-resource DINE lookup (backupprotecteditems)
# - Deployment template with nested deployment
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure backup on virtual machines without a given tag to an existing recovery services vault in the same location",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"vaultLocation": {
"type": "String"
},
"backupPolicyId": {
"type": "String"
},
"exclusionTagName": {
"type": "String",
"defaultValue": ""
},
"exclusionTagValue": {
"type": "Array",
"defaultValue": []
},
"effect": {
"type": "String",
"allowedValues": [
"auditIfNotExists",
"AuditIfNotExists",
"deployIfNotExists",
"DeployIfNotExists",
"disabled",
"Disabled"
],
"defaultValue": "DeployIfNotExists"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "location",
"equals": "[parameters('vaultLocation')]"
},
{
"field": "id",
"notContains": "/resourceGroups/databricks-rg-"
},
{
"field": "Microsoft.Compute/imagePublisher",
"notEquals": "azureopenshift"
},
{
"field": "Microsoft.Compute/imagePublisher",
"notEquals": "AzureDatabricks"
},
{
"anyOf": [
{
"not": {
"field": "[concat('tags[', parameters('exclusionTagName'), ']')]",
"in": "[parameters('exclusionTagValue')]"
}
},
{
"value": "[empty(parameters('exclusionTagValue'))]",
"equals": "true"
},
{
"value": "[empty(parameters('exclusionTagName'))]",
"equals": "true"
}
]
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftWindowsServer"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "WindowsServer"
},
{
"field": "Microsoft.Compute/imageSKU",
"in": [
"2008-R2-SP1",
"2008-R2-SP1-smalldisk",
"2012-Datacenter",
"2012-Datacenter-smalldisk",
"2012-R2-Datacenter",
"2012-R2-Datacenter-smalldisk",
"2016-Datacenter",
"2016-datacenter-gensecond",
"2016-Datacenter-Server-Core",
"2016-Datacenter-Server-Core-smalldisk",
"2016-Datacenter-smalldisk",
"2016-Datacenter-with-Containers",
"2016-Datacenter-with-RDSH",
"2019-Datacenter",
"2019-Datacenter-Core",
"2019-Datacenter-Core-smalldisk",
"2019-Datacenter-Core-with-Containers",
"2019-Datacenter-Core-with-Containers-smalldisk",
"2019-Datacenter-smalldisk",
"2019-Datacenter-with-Containers",
"2019-Datacenter-with-Containers-smalldisk",
"2019-Datacenter-zhcn",
"2019-datacenter-gensecond",
"2022-datacenter-g2",
"2022-datacenter",
"2022-datacenter-azure-edition",
"2022-datacenter-azure-edition-smalldisk",
"2022-datacenter-azure-edition-core",
"2022-datacenter-azure-edition-core-smalldisk",
"2022-datacenter-smalldisk-g2",
"2022-datacenter-smalldisk",
"2022-datacenter-core-g2",
"2022-datacenter-core",
"2022-datacenter-core-smalldisk-g2",
"2022-datacenter-core-smalldisk"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftWindowsServer"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "WindowsServerSemiAnnual"
},
{
"field": "Microsoft.Compute/imageSKU",
"in": [
"Datacenter-Core-1709-smalldisk",
"Datacenter-Core-1709-with-Containers-smalldisk",
"Datacenter-Core-1803-with-Containers-smalldisk"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftWindowsServerHPCPack"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "WindowsServerHPCPack"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftSQLServer"
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.Compute/imageOffer",
"like": "sql2019-ws2022"
},
{
"field": "Microsoft.Compute/imageSKU",
"in": [
"sqldev",
"sqldev-gen2",
"standard",
"standard-gen2"
]
}
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageOffer",
"like": "*-WS2019"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "*-WS2016"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "*-WS2016-BYOL"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "*-WS2012R2"
},
{
"field": "Microsoft.Compute/imageOffer",
"like": "*-WS2012R2-BYOL"
}
]
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftRServer"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "MLServer-WS2016"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftVisualStudio"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"VisualStudio",
"Windows"
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftDynamicsAX"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "Dynamics"
},
{
"field": "Microsoft.Compute/imageSKU",
"equals": "Pre-Req-AX7-Onebox-U8"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "microsoft-ads"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "windows-data-science-vm"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftWindowsDesktop"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "Windows-10"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "MicrosoftWindowsDesktop"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "Windows-11"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "RedHat"
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.Compute/imageOffer",
"equals": "RHEL-BYOS"
},
{
"field": "Microsoft.Compute/imageSKU",
"equals": "rhel-lvm77"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"RHEL",
"RHEL-SAP-HANA"
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSKU",
"like": "6.*"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "7*"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "8*"
}
]
}
]
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "SUSE"
},
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"SLES",
"SLES-HPC",
"SLES-HPC-Priority",
"SLES-SAP",
"SLES-SAP-BYOS",
"SLES-Priority",
"SLES-BYOS",
"SLES-SAPCAL",
"SLES-Standard"
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSKU",
"like": "12*"
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Canonical"
},
{
"field": "Microsoft.Compute/imageOffer",
"contains": "ubuntu"
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSKU",
"like": "14.04*LTS"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "16.04*LTS"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "18.04*LTS"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "*20_04-lts"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "20_04-lts*"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "22_04-lts-gen2"
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "Oracle"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "Oracle-Linux"
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSKU",
"like": "6.*"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "7*"
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "OpenLogic"
},
{
"anyOf": [
{
"allOf": [
{
"field": "Microsoft.Compute/imageOffer",
"equals": "CentOS-HPC"
},
{
"field": "Microsoft.Compute/imageSKU",
"equals": "7_9-gen2"
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imageOffer",
"in": [
"CentOS",
"Centos-LVM",
"CentOS-SRIOV"
]
},
{
"anyOf": [
{
"field": "Microsoft.Compute/imageSKU",
"like": "6.*"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "7*"
}
]
}
]
}
]
}
]
},
{
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"equals": "cloudera"
},
{
"field": "Microsoft.Compute/imageOffer",
"equals": "cloudera-centos-os"
},
{
"field": "Microsoft.Compute/imageSKU",
"like": "7*"
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c",
"/providers/microsoft.authorization/roleDefinitions/5e467623-bb1f-42f4-a55d-6e525e11384b"
],
"type": "Microsoft.RecoveryServices/backupprotecteditems",
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"backupPolicyId": {
"type": "String"
},
"fabricName": {
"type": "String"
},
"protectionContainers": {
"type": "String"
},
"protectedItems": {
"type": "String"
},
"sourceResourceId": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2017-05-10",
"name": "[concat('DeployProtection-',uniqueString(parameters('protectedItems')))]",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[first(skip(split(parameters('backupPolicyId'), '/'), 4))]",
"subscriptionId": "[first(skip(split(parameters('backupPolicyId'), '/'), 2))]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"backupPolicyId": {
"type": "String"
},
"fabricName": {
"type": "String"
},
"protectionContainers": {
"type": "String"
},
"protectedItems": {
"type": "String"
},
"sourceResourceId": {
"type": "String"
}
},
"resources": [
{
"type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems",
"name": "[concat(first(skip(split(parameters('backupPolicyId'), '/'), 8)), '/', parameters('fabricName'), '/',parameters('protectionContainers'), '/', parameters('protectedItems'))]",
"apiVersion": "2016-06-01",
"properties": {
"protectedItemType": "Microsoft.Compute/virtualMachines",
"policyId": "[parameters('backupPolicyId')]",
"sourceResourceId": "[parameters('sourceResourceId')]"
}
}
]
},
"parameters": {
"backupPolicyId": {
"value": "[parameters('backupPolicyId')]"
},
"fabricName": {
"value": "[parameters('fabricName')]"
},
"protectionContainers": {
"value": "[parameters('protectionContainers')]"
},
"protectedItems": {
"value": "[parameters('protectedItems')]"
},
"sourceResourceId": {
"value": "[parameters('sourceResourceId')]"
}
}
}
}
]
},
"parameters": {
"backupPolicyId": {
"value": "[parameters('backupPolicyId')]"
},
"fabricName": {
"value": "Azure"
},
"protectionContainers": {
"value": "[concat('iaasvmcontainer;iaasvmcontainerv2;', resourceGroup().name, ';' ,field('name'))]"
},
"protectedItems": {
"value": "[concat('vm;iaasvmcontainerv2;', resourceGroup().name, ';' ,field('name'))]"
},
"sourceResourceId": {
"value": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/',field('name'))]"
}
}
}
}
}
}
}
}
}
cases:
# =========================================================================
# VM without backup → no related backupprotecteditems → DeployIfNotExists
# (default empty exclusion tag params → empty() branches pass the anyOf)
# =========================================================================
- note: dine_vm_no_backup
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-no-backup"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.RecoveryServices/backupprotecteditems"
response: null
want_effect: "DeployIfNotExists"
want_details:
roleDefinitionIds:
- "/providers/microsoft.authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"
- "/providers/microsoft.authorization/roleDefinitions/5e467623-bb1f-42f4-a55d-6e525e11384b"
type: "Microsoft.RecoveryServices/backupprotecteditems"
# =========================================================================
# VM with existing backup → backupprotecteditems found → compliant (pass)
# =========================================================================
- note: pass_vm_with_backup
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-has-backup"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
host_await:
- response:
properties:
protectedItemType: "Microsoft.Compute/virtualMachines"
policyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
sourceResourceId: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm-has-backup"
want_undefined: true
# =========================================================================
# VM with exclusion tag matching parameter value → excluded from scope → pass
# Tag "backup-opt-out" = "true" is IN exclusionTagValue ["true", "yes"]
# → not(in) = false, empty(tagValue) = false, empty(tagName) = false
# → anyOf fails → allOf fails → if-condition false → pass
# =========================================================================
- note: pass_vm_excluded_by_tag
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-excluded-tag"
location: "eastus"
tags:
backup-opt-out: "true"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
exclusionTagName: "backup-opt-out"
exclusionTagValue:
- "true"
- "yes"
want_undefined: true
# =========================================================================
# VM with excluded publisher "AzureDatabricks" → notEquals fails → pass
# =========================================================================
- note: pass_vm_excluded_publisher
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-databricks"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "AzureDatabricks"
offer: "databricks"
sku: "standard"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
want_undefined: true
# =========================================================================
# Wrong resource type → type check fails → pass
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "storage1"
location: "eastus"
properties: {}
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
want_undefined: true
# =========================================================================
# VM has exclusion tag but value NOT in exclusion list → still in scope
# Tag "backup-opt-out" = "no" is NOT IN ["true", "yes"]
# → not(in) = true → anyOf passes → VM is in scope → DINE
# =========================================================================
- note: dine_vm_tag_not_in_exclusion
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-tag-no-match"
location: "eastus"
tags:
backup-opt-out: "no"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
exclusionTagName: "backup-opt-out"
exclusionTagValue:
- "true"
- "yes"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.RecoveryServices/backupprotecteditems"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# VM in a different location than vaultLocation → location check fails → pass
# =========================================================================
- note: pass_vm_wrong_location
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-wrong-loc"
location: "westeurope"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
want_undefined: true
# =========================================================================
# VM in a Databricks resource group → notContains "/resourceGroups/databricks-rg-"
# fails → allOf fails → pass
# =========================================================================
- note: pass_vm_databricks_rg
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-dbr"
id: "/subscriptions/sub1/resourceGroups/databricks-rg-myworkspace/providers/Microsoft.Compute/virtualMachines/vm-dbr"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "MicrosoftWindowsServer"
offer: "WindowsServer"
sku: "2019-Datacenter"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
want_undefined: true
# =========================================================================
# VM with publisher "azureopenshift" → notEquals fails → allOf fails → pass
# =========================================================================
- note: pass_vm_excluded_publisher_azureopenshift
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-openshift"
location: "eastus"
properties:
storageProfile:
imageReference:
publisher: "azureopenshift"
offer: "aro4"
sku: "aro_worker"
parameters:
vaultLocation: "eastus"
backupPolicyId: "/subscriptions/sub1/resourceGroups/backup-rg/providers/Microsoft.RecoveryServices/vaults/vault1/backupPolicies/DefaultPolicy"
want_undefined: true

View File

@@ -0,0 +1,156 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Compute/VMRequireManagedDisk_Audit
# Real Azure Policy: "Audit VMs that do not use managed disks"
# Features: anyOf, allOf nesting, field (type + alias), equals, exists,
# multiple resource types (VM + VMSS)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Audit VMs that do not use managed disks",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {},
"policyRule": {
"if": {
"anyOf": [
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "Microsoft.Compute/virtualMachines/osDisk.uri",
"exists": "True"
}
]
},
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/VirtualMachineScaleSets"
},
{
"anyOf": [
{
"field": "Microsoft.Compute/VirtualMachineScaleSets/osDisk.vhdContainers",
"exists": "True"
},
{
"field": "Microsoft.Compute/VirtualMachineScaleSets/osdisk.imageUrl",
"exists": "True"
}
]
}
]
}
]
},
"then": {
"effect": "audit"
}
}
}
}
cases:
# =========================================================================
# Audit — VM with unmanaged OS disk (vhd uri present)
# =========================================================================
- note: audit_vm_unmanaged_osdisk
resource:
type: "Microsoft.Compute/virtualMachines"
name: "legacyVM"
location: "eastus"
properties:
storageProfile:
osDisk:
vhd:
uri: "https://mystorage.blob.core.windows.net/vhds/osdisk.vhd"
want_effect: "audit"
# =========================================================================
# No effect — VM with managed disk (no vhd uri)
# =========================================================================
- note: pass_vm_managed_disk
resource:
type: "Microsoft.Compute/virtualMachines"
name: "modernVM"
location: "eastus"
properties:
storageProfile:
osDisk:
managedDisk:
storageAccountType: "Premium_LRS"
want_undefined: true
# =========================================================================
# Audit — VMSS with vhdContainers (unmanaged)
# =========================================================================
- note: audit_vmss_vhd_containers
resource:
type: "Microsoft.Compute/VirtualMachineScaleSets"
name: "legacyScaleSet"
location: "westus"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
vhdContainers:
- "https://stor1.blob.core.windows.net/vhds"
want_effect: "audit"
# =========================================================================
# Audit — VMSS with custom image URL (unmanaged)
# =========================================================================
- note: audit_vmss_image_url
resource:
type: "Microsoft.Compute/VirtualMachineScaleSets"
name: "customImgScaleSet"
location: "westus"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
image:
uri: "https://mystorage.blob.core.windows.net/images/custom.vhd"
want_effect: "audit"
# =========================================================================
# No effect — VMSS with managed disk (no vhdContainers, no imageUrl)
# =========================================================================
- note: pass_vmss_managed_disk
resource:
type: "Microsoft.Compute/VirtualMachineScaleSets"
name: "modernScaleSet"
location: "eastus"
properties:
virtualMachineProfile:
storageProfile:
osDisk:
managedDisk:
storageAccountType: "Standard_LRS"
want_undefined: true
# =========================================================================
# No effect — wrong resource type entirely
# =========================================================================
- note: skip_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "myStorage"
location: "eastus"
properties: {}
want_undefined: true

View File

@@ -0,0 +1,342 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Compute/VirtualMachineReplication_AzureSiteRecovery_DINE
# Real Azure Policy: "Configure disaster recovery on virtual machines by
# enabling replication via Azure Site Recovery"
# Source: regolator/policyDefinitions/Compute/VirtualMachineReplication_AzureSiteRecovery_DINE.json
#
# Features exercised:
# - DeployIfNotExists effect
# - concat('tags[', parameters('tagName'), ']') — dynamic tag field access
# - empty() function for Boolean branching
# - in / notIn operators on tag values
# - Multi-branch anyOf/allOf with parameterised control flow
# - existenceCondition with like + contains operators
# - host_await for cross-resource lookup
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Configure disaster recovery on virtual machines",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"sourceRegion": {
"type": "String"
},
"targetRegion": {
"type": "String"
},
"targetResourceGroupId": {
"type": "String"
},
"vaultResourceGroupId": {
"type": "String"
},
"vaultId": {
"type": "String"
},
"recoveryNetworkId": {
"type": "String",
"defaultValue": ""
},
"targetZone": {
"type": "String",
"defaultValue": ""
},
"cacheStorageAccountId": {
"type": "String",
"defaultValue": ""
},
"tagName": {
"type": "String",
"defaultValue": ""
},
"tagValue": {
"type": "Array",
"defaultValue": []
},
"tagType": {
"type": "String",
"allowedValues": ["Inclusion", "Exclusion", ""],
"defaultValue": ""
},
"effect": {
"type": "String",
"allowedValues": ["DeployIfNotExists", "Disabled"],
"defaultValue": "DeployIfNotExists"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "location",
"equals": "[parameters('sourceRegion')]"
},
{
"anyOf": [
{
"allOf": [
{
"value": "[parameters('tagType')]",
"equals": "Inclusion"
},
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"in": "[parameters('tagValue')]"
}
]
},
{
"allOf": [
{
"value": "[parameters('tagType')]",
"equals": "Exclusion"
},
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"notIn": "[parameters('tagValue')]"
}
]
},
{
"anyOf": [
{
"value": "[empty(parameters('tagName'))]",
"equals": "true"
},
{
"value": "[empty(parameters('tagValue'))]",
"equals": "true"
},
{
"value": "[empty(parameters('tagType'))]",
"equals": "true"
}
]
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Resources/links",
"existenceCondition": {
"allOf": [
{
"field": "name",
"like": "ASR-Policy-Protect-*"
},
{
"field": "Microsoft.Resources/links/targetId",
"contains": "/replicationProtectedItems/"
}
]
}
}
}
}
}
}
cases:
# =========================================================================
# No tag filters (all params empty) → matches, related resource not found → DINE
# =========================================================================
- note: dine_no_tag_filter_no_related
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-no-dr"
location: "eastus"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Resources/links"
response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# No tag filter, related resource found with matching name/targetId → compliant
# =========================================================================
- note: compliant_dr_configured
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-dr-ok"
location: "eastus"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
host_await:
- response:
name: "ASR-Policy-Protect-vm-dr-ok"
properties:
targetid: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1/replicationProtectedItems/item1"
want_undefined: true
# =========================================================================
# Related resource found but name doesn't match like → DINE
# =========================================================================
- note: dine_wrong_link_name
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-wrong-link"
location: "eastus"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
host_await:
- response:
name: "some-other-link"
properties:
targetid: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1/replicationProtectedItems/item1"
want_effect: "DeployIfNotExists"
# =========================================================================
# Inclusion tag type — VM has matching tag → if-condition matches
# =========================================================================
- note: dine_inclusion_tag_match
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-tagged"
location: "eastus"
tags:
Environment: "production"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
tagName: "Environment"
tagValue:
- "production"
- "staging"
tagType: "Inclusion"
host_await:
- response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Inclusion tag type — VM tag doesn't match → if-condition fails → pass
# =========================================================================
- note: pass_inclusion_tag_no_match
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-dev"
location: "eastus"
tags:
Environment: "development"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
tagName: "Environment"
tagValue:
- "production"
- "staging"
tagType: "Inclusion"
want_undefined: true
# =========================================================================
# Exclusion tag type — VM tag in exclusion list → pass (excluded from scope)
# =========================================================================
- note: pass_exclusion_tag_excluded
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-excluded"
location: "eastus"
tags:
Environment: "sandbox"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
tagName: "Environment"
tagValue:
- "sandbox"
- "test"
tagType: "Exclusion"
want_undefined: true
# =========================================================================
# Exclusion tag type — VM tag NOT in exclusion list → matches → DINE
# =========================================================================
- note: dine_exclusion_tag_not_excluded
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-prod-excl"
location: "eastus"
tags:
Environment: "production"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
tagName: "Environment"
tagValue:
- "sandbox"
- "test"
tagType: "Exclusion"
host_await:
- response: null
want_effect: "DeployIfNotExists"
# =========================================================================
# Wrong location → if-condition fails → pass
# =========================================================================
- note: pass_wrong_location
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm-wrong-loc"
location: "westus"
properties: {}
parameters:
sourceRegion: "eastus"
targetRegion: "westus"
targetResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-dr"
vaultResourceGroupId: "/subscriptions/sub1/resourceGroups/rg-vault"
vaultId: "/subscriptions/sub1/resourceGroups/rg-vault/providers/Microsoft.RecoveryServices/vaults/vault1"
want_undefined: true

View File

@@ -0,0 +1,150 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Compute/VMSkusAllowed_Deny
# Real Azure Policy: "Allowed virtual machine size SKUs"
# Features: allOf, not, field (type + alias), equals, in, parameters()
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Allowed virtual machine size SKUs",
"policyType": "BuiltIn",
"mode": "Indexed",
"parameters": {
"listOfAllowedSKUs": {
"type": "Array",
"metadata": {
"displayName": "Allowed Size SKUs"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"not": {
"field": "Microsoft.Compute/virtualMachines/sku.name",
"in": "[parameters('listOfAllowedSKUs')]"
}
}
]
},
"then": {
"effect": "Deny"
}
}
}
}
cases:
# =========================================================================
# Deny — VM SKU not in allowed list
# =========================================================================
- note: deny_disallowed_sku
resource:
type: "Microsoft.Compute/virtualMachines"
name: "myVM"
location: "eastus"
properties:
hardwareProfile:
vmSize: "Standard_E64i_v3"
parameters:
listOfAllowedSKUs:
- "Standard_D2s_v3"
- "Standard_D4s_v3"
- "Standard_D8s_v3"
want_effect: "Deny"
# =========================================================================
# No effect — VM SKU is in allowed list
# =========================================================================
- note: allow_permitted_sku
resource:
type: "Microsoft.Compute/virtualMachines"
name: "myVM"
location: "eastus"
properties:
hardwareProfile:
vmSize: "Standard_D4s_v3"
parameters:
listOfAllowedSKUs:
- "Standard_D2s_v3"
- "Standard_D4s_v3"
- "Standard_D8s_v3"
want_undefined: true
# =========================================================================
# No effect — wrong resource type (not a VM)
# =========================================================================
- note: skip_wrong_resource_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "myStorage"
location: "eastus"
properties: {}
parameters:
listOfAllowedSKUs:
- "Standard_D2s_v3"
want_undefined: true
# =========================================================================
# Deny — single allowed SKU, VM doesn't match
# =========================================================================
- note: deny_single_allowed_sku
resource:
type: "Microsoft.Compute/virtualMachines"
name: "bigVM"
location: "westus"
properties:
hardwareProfile:
vmSize: "Standard_M128s"
parameters:
listOfAllowedSKUs:
- "Standard_B1s"
want_effect: "Deny"
# =========================================================================
# No effect — empty allowed list means everything blocked? No: `in` with
# empty array is always false → not(false)=true → Deny.
# =========================================================================
- note: deny_empty_allowed_list
resource:
type: "Microsoft.Compute/virtualMachines"
name: "anyVM"
location: "eastus"
properties:
hardwareProfile:
vmSize: "Standard_D2s_v3"
parameters:
listOfAllowedSKUs: []
want_effect: "Deny"
# =========================================================================
# Case sensitivity — SKU names are compared case-insensitively by the
# `in` operator (Azure Policy string comparison semantics)
# =========================================================================
- note: allow_case_insensitive_sku
resource:
type: "Microsoft.Compute/virtualMachines"
name: "myVM"
location: "eastus"
properties:
hardwareProfile:
vmSize: "standard_d4s_v3"
parameters:
listOfAllowedSKUs:
- "Standard_D4s_v3"
want_undefined: true

View File

@@ -0,0 +1,157 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# E2E Test: Network/VirtualNetworkDdosStandard_Audit
# Real Azure Policy: "Virtual networks should be protected by Azure DDoS Protection"
# Source: regolator/policyDefinitions/Network/VirtualNetworkDdosStandard_Audit.json
#
# Features exercised:
# - Modify effect with operations (addOrReplace)
# - anyOf within allOf (enableDdosProtection OR ddosProtectionPlan empty)
# - Parameterized effect with Modify/Audit/Disabled
# - conflictEffect in details
# - field equals "" (empty string check)
aliases: test_aliases.json
policy_definition: |
{
"properties": {
"displayName": "Virtual networks should be protected by Azure DDoS Protection",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {
"effect": {
"type": "String",
"allowedValues": ["Modify", "Audit", "Disabled"],
"defaultValue": "Modify"
},
"ddosPlan": {
"type": "String",
"metadata": {
"displayName": "DDoS Protection Plan",
"strongType": "Microsoft.Network/ddosProtectionPlans"
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/virtualNetworks"
},
{
"anyOf": [
{
"field": "Microsoft.Network/virtualNetworks/enableDdosProtection",
"notEquals": true
},
{
"field": "Microsoft.Network/virtualNetworks/ddosProtectionPlan",
"equals": ""
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"conflictEffect": "audit",
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
],
"operations": [
{
"operation": "addOrReplace",
"field": "Microsoft.Network/virtualNetworks/enableDdosProtection",
"value": true
},
{
"operation": "addOrReplace",
"field": "Microsoft.Network/virtualNetworks/ddosProtectionPlan.id",
"value": "[parameters('ddosPlan')]"
}
]
}
}
}
}
}
cases:
# =========================================================================
# Non-compliant: DDoS not enabled
# =========================================================================
- note: modify_ddos_not_enabled
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-no-ddos"
properties:
enableDdosProtection: false
ddosProtectionPlan: ""
parameters:
ddosPlan: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/ddosProtectionPlans/plan1"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/microsoft.authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
operations:
- operation: "addOrReplace"
field: "Microsoft.Network/virtualNetworks/enableDdosProtection"
value: true
- operation: "addOrReplace"
field: "Microsoft.Network/virtualNetworks/ddosProtectionPlan.id"
value: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/ddosProtectionPlans/plan1"
- note: modify_ddos_enabled_but_no_plan
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-no-plan"
properties:
enableDdosProtection: true
ddosProtectionPlan: ""
parameters:
ddosPlan: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/ddosProtectionPlans/plan1"
want_effect: "Modify"
- note: modify_ddos_missing_field
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-missing"
properties: {}
parameters:
ddosPlan: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/ddosProtectionPlans/plan1"
want_effect: "Modify"
# =========================================================================
# Compliant: DDoS enabled with plan
# =========================================================================
- note: pass_ddos_enabled_with_plan
resource:
type: "Microsoft.Network/virtualNetworks"
name: "vnet-protected"
properties:
enableDdosProtection: true
ddosProtectionPlan:
id: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/ddosProtectionPlans/plan1"
parameters:
ddosPlan: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/ddosProtectionPlans/plan1"
want_undefined: true
# =========================================================================
# Wrong type
# =========================================================================
- note: pass_wrong_type
resource:
type: "Microsoft.Storage/storageAccounts"
name: "not-a-vnet"
properties:
enableDdosProtection: false
parameters:
ddosPlan: "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Network/ddosProtectionPlans/plan1"
want_undefined: true