hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.5k stars 4.59k forks source link

Policy Resources Optional Parameters State Mismatch #21048

Open d-jaquay opened 1 year ago

d-jaquay commented 1 year ago

Is there an existing issue for this?

Community Note

Terraform Version

1.3.5

AzureRM Provider Version

3.5.0

Affected Resource(s)/Data Source(s)

azurerm_policy_set_definition & azurerm_management_group_policy_assignment

Terraform Configuration Files

resource "azurerm_management_group_policy_assignment" "example" {
  name                 = "example-policy"
  policy_definition_id = azurerm_policy_definition.example.id
  management_group_id  = azurerm_management_group.example.id
}

resource "azurerm_policy_set_definition" "example" {
  name         = "testPolicySet"
  policy_type  = "Custom"
  display_name = "Test Policy Set"

  policy_definition_reference {
    policy_definition_id = "POLICY-DEFINITION-ID"
  }

Debug Output/Panic Output

N/A

Expected Behaviour

Resources are deployed with no future changes.

Actual Behaviour

Subsequent plan runs of Terraform try to remove "parameters" from azurerm_management_group_policy_assignment and "parameter_values" from the "policy_definition_reference" block in the azurerm_policy_set_definition resource. image

Looking at the state file both of these values are stored as empty strings (ex. parameters: ""). Azure API appears to be returning "parameters: jsonencode({})" for the value which is causing this mismatch.

image

Steps to Reproduce

  1. Create Azure policy resources with no parameters & parameter_values set
  2. terraform apply
  3. terraform plan

Important Factoids

No response

References

No response

d-jaquay commented 1 year ago

From our testing it looks like this is a gap between the AzureRM provider and the Azure API. Any policy or definition/initiative that is edited today appears set the optional "parameters" value to be empty json (ex. "{}") but the provider currently assumes that this optional parameters value will be an empty string. Causing the plan phase to never match current state if you do not provide a value.

wuxu92 commented 1 year ago

hi @d-jaquay could you please share the configuration of the azurerm_policy_definition resource? i have tries with a custom azurerm_policy_definition and i cannot reproduce this.

b-rand commented 1 year ago

hi @d-jaquay could you please share the configuration of the azurerm_policy_definition resource? i have tries with a custom azurerm_policy_definition and i cannot reproduce this.

Hi @wuxu92, We are seeing this issue with the azurerm_policy_set_definition and azurerm_management_group_policy_assignment resources. Most/all of the azurerm_policy_definition resources we create use the parameters attribute, so we have not seen this issue with the azurerm_policy_definition resources.

The example azurerm_management_group_policy_assignment above uses builtin policy definitions in Azure to create the policy set/initiative. Here is a list of the builtin policies that are included.

To reproduce this issue, you could create an azurerm_policy_set_definition resource that does not include the parameters property, the included azurerm_policy_definition should not matter in this case. If you do not see the mismatched state immediately on the next apply, we found clicking edit and save in the Azure Portal will cause the resource to be in this state of needing to be updated every subsequent run.

wuxu92 commented 1 year ago

hi @b-rand thanks for you information! do you mean that clickign edit and save without modifing in azure portal will cause a need of updated in terraform? i wonder if the save action in portal actually updated the resource (like change the value from "" to {}). and i believe this is somewhat expected.

b-rand commented 1 year ago

Hi @wuxu92, Clicking edit and save in the portal is one way to reproduce this issue. Another way is to create either an azurerm_policy_set_definition or an azurerm_management_group_policy_assignment without including any value for parameters or the parameter_values. Afterwards, if you run a plan only, you will see the mismatch where terraform wants the value of those arguments to be "" but the Azure API is returning jsonencode({ }).

As a workaround, we have included the value jsonencode({}) for the optional parameters when we are editing existing policy resources or creating new ones. The Azure API accepts this as a valid input and our state file then matches the resources within Azure. Below is an example of this.

resource "azurerm_management_group_policy_assignment" "example" {
  name                 = "example"
  management_group_id  = var.mgmt-grp-id
  policy_definition_id = var.policy-definition-id
  description          = "Example"
  display_name         = "Example"
  location             = var.location
  parameters           = jsonencode({})
  identity { type = "SystemAssigned" }
}