I'm currently creating an Azure Policy that (is supposed to) deploys Microsoft Defender for Servers with Plan P1 if the current plan is different. Many subscriptions that I have currently have Microsoft Defender for Servers enabled, but use plan P2 instead of P1, so I created a policy with DeployIfNotExists that should change the values to the correct one, but it is not working as expected.
The policy is as follows (I'm using Terraform):
resource "azurerm_policy_definition" "dfservers_policy" {
name = "defenderForServers"
policy_type = "Custom"
mode = "All"
display_name = "Deploy Azure Defender for servers with plan"
description = "Azure Defender for servers provides real-time threat protection for server workloads and generates hardening recommendations as well as alerts about suspicious activities."
management_group_id = data.azurerm_management_group.root_management_group.id
metadata = <<METADATA
{
"category": "Security Center"
}
METADATA
policy_rule = <<POLICY_RULE
{
"if": {
"field": "type",
"equals": "Microsoft.Resources/subscriptions"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Security/pricings",
"name": "VirtualMachines",
"deploymentScope": "subscription",
"existenceScope": "subscription",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
],
"existenceCondition": {
"allOf": [
{
"field": "Microsoft.Security/pricings/pricingTier",
"equals": "Standard"
},
{
"field": "Microsoft.Security/pricings/subPlan",
"equals": "[parameters('plan_type')]"
}
]
},
"deployment": {
"location": "westeurope",
"properties": {
"mode": "incremental",
"parameters": {
"plan_type": {
"value": "[parameters('plan_type')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"plan_type": {
"type": "String",
"metadata": {
"displayName": "Server Plan Type",
"description": "Define which plan type to use. Either P1 or P2"
},
"allowedValues": [
"P1",
"P2"
],
"defaultValue": "P2"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Security/pricings",
"apiVersion": "2018-06-01",
"name": "VirtualMachines",
"properties": {
"pricingTier": "Standard",
"subPlan": "[parameters('plan_type')]"
}
}
],
"outputs": {}
}
}
}
}
}
}
POLICY_RULE
parameters = <<PARAMETERS
{
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
},
"allowedValues": [
"DeployIfNotExists",
"Disabled"
],
"defaultValue": "DeployIfNotExists"
},
"plan_type": {
"type": "String",
"metadata": {
"displayName": "Server Plan Type",
"description": "Define which plan type to use. Either P1 or P2"
},
"allowedValues": [
"P1",
"P2"
],
"defaultValue": "P2"
}
}
PARAMETERS
}
And the assignment is as follows:
resource "azurerm_management_group_policy_assignment" "dfserver_sandbox_assignment" {
name = "Def4ServersSB"
display_name = "Deploy 'Defender for Servers' with Plan P1"
location = var.location
policy_definition_id = azurerm_policy_definition.dfservers_policy.id
management_group_id = data.azurerm_management_group.sandbox_management_group.id
identity {
type = "SystemAssigned"
}
parameters = jsonencode({
"plan_type": {
"value": "P1"
},
})
}
I have also attached the Security Admin role to the System Managed Identity as there seems to be a bug regarding it:
# This is needed due to a bug where the automatically created System Managed Identity does not have the required permissions (https://github.com/hashicorp/terraform-provider-azurerm/issues/6486)
resource "azurerm_role_assignment" "ra_dfserver_sandbox" {
scope = azurerm_management_group_policy_assignment.dfserver_sandbox_assignment.management_group_id
role_definition_name = "Security Admin"
principal_id = azurerm_management_group_policy_assignment.dfserver_sandbox_assignment.identity[0].principal_id
}
After a bit of time the policy seems to work as expected, picking up a few non-complaint subscriptions: Non compliant subscriptions
I'm also able to create a remediation task and run it successfully: Deployment list
All good then, right? Nah. If go and check the values for the subscription I can see that it is still P2: Old values continue
Maybe there was an error and the parameter is setup as P2 instead of P1? Nope: Deployment Value
Maybe for some reason the deployment didn't run? This is my current thesis, but on the activity log of the values this shows up: Activity Log
Do you guys have any idea why this might be happening? Any light would be really appreciated :)
Your are using an old API version for Microsoft.Security/pricings, update your template to use API version 2022-03-01