Azure Policy Exemption on Management Group using Terraform.
Problem
To assign an Azure policy exception in Terraform using azurerm_resource_group_policy_exemption
you need to specify the scope. This works fine if you specify a Resource Group ID, but will fail when you specify the scope as a Management Group ID. The Management Group ID (for example corp
) or even the extended id (for example /providers/microsoft.management/managementgroups/corp/
) fail with an error:
1│ Error: parsing "corp": parsing the ResourceGroup ID: the number of segments didn't match
2│
3│ Expected a ResourceGroup ID that matched (containing 4 segments):
4│
5│ > /subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group
6│
7│ However this value was provided (which was parsed into 0 segments):
8│
9│ > corp
10│
11│ The following Segments are expected:
12│
13│ * Segment 0 - this should be the literal value "subscriptions"
14│ * Segment 1 - this should be the UUID of the Azure Subscription
15│ * Segment 2 - this should be the literal value "resourceGroups"
16│ * Segment 3 - this should be the name of the Resource Group
17│
18│ The following Segments were parsed:
19│
20│ * Segment 0 - not found
21│ * Segment 1 - not found
22│ * Segment 2 - not found
23│ * Segment 3 - not found
24│
Cause
The management group ID doesn’t follow the same format as a Resource Group ID:
1/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group
so is rejected by the Terraform validation.
Solution
A workaround is needed to have the ID accepted. This can be done with a data block referencing the Management Group (in this case corp
) and using the ID of that object for the scope when looking up the data block for the Assignment. The Exemption (in this case using a Resource Group) then works as normal.
1#Lookup Management Group
2data "azurerm_management_group" "corp" {
3 name = "corp"
4}
5
6#Lookup Policy Assignment
7data "azurerm_policy_assignment" "example" {
8 scope_id = data.azurerm_management_group.corp.id
9 #Resolves to "/providers/Microsoft.Management/managementGroups/corp"
10 name = "example-policy-name"
11}
12
13#Define Exemption
14resource "azurerm_resource_group_policy_exemption" "example" {
15 name = "example-exemption"
16 resource_group_id = azurerm_resource_group.rg.id
17 policy_assignment_id = data.azurerm_policy_assignment.example.id
18 exemption_category = "Mitigated"
19}
Using this method bypasses the string format validation on the ID value and enables the plan and apply to work.