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.6k stars 4.64k forks source link

Firewall Policy Rule Collection Group deleting and recreating all the rules if new added #22371

Open shlomimn opened 1 year ago

shlomimn commented 1 year ago

Is there an existing issue for this?

Community Note

Terraform Version

1.4.6

AzureRM Provider Version

3.58.0

Affected Resource(s)/Data Source(s)

azurerm_firewall_policy_rule_collection_group

Terraform Configuration Files

name                   = "fw-net-rule"
location               = "eastus"
azure_firewall_name    = "eastus-firewall-mgmt"
firewall_policy_name   = "eastus-firewall-policy-mgmt"
action                 = "Allow"
resource_group_name    = "eastus-rg-vgw"
rule-collection-groups = {
  "allow-new-rules" = {
    priority                = 14000
    network_rule_collection = {
      "allow-new-rules" = {
        priority = 100
        action   = "Allow"
        rules    = {
          "aaa" = {
            source_addresses      = ["10.10.10.10/32"]
            destination_ports     = ["443"]
            destination_addresses = ["10.20.20.20/32"]
            protocols             = ["TCP"]
          }
          "bbb" = {
            source_addresses      = ["10.10.10.10/32"]
            destination_ports     = ["443"]
            destination_addresses = ["10.21.21.21/32"]
            protocols             = ["TCP"]
          }
          "ccc" = {
            source_addresses      = ["10.10.10.10/32"]
            destination_ports     = ["443"]
            destination_addresses = ["10.30.30.30/32"]
            protocols             = ["TCP"]
          }
          "ddd" = {
            source_addresses      = ["10.10.10.10/32"]
            destination_ports     = ["443"]
            destination_addresses = ["10.40.40.40/32"]
            protocols             = ["TCP"]
          }
        }
      }
    }
  }
}

Debug Output/Panic Output

Terraform will perform the following actions:

  # module.firewall-rules["allow-new-rules"].azurerm_firewall_policy_rule_collection_group.this will be updated in-place
  ~ resource "azurerm_firewall_policy_rule_collection_group" "this" {
        id                 = "/subscriptions/c4dd7de0-a3f0-4026-870d-501454d2fa2c/resourceGroups/eastus-rg-vgw/providers/Microsoft.Network/firewallPolicies/eastus-firewall-policy-mgmt/ruleCollectionGroups/allow-new-rules"
        name               = "allow-new-rules"
        # (2 unchanged attributes hidden)

      ~ network_rule_collection {
            name     = "allow-new-rules"
            # (2 unchanged attributes hidden)

          ~ rule {
              ~ destination_addresses = [
                  - "10.30.30.30/32",
                  + "10.21.21.21/32",
                ]
              ~ name                  = "ccc" -> "bbb"
                # (6 unchanged attributes hidden)
            }
          ~ rule {
              ~ destination_addresses = [
                  - "10.40.40.40/32",
                  + "10.30.30.30/32",
                ]
              ~ name                  = "ddd" -> "ccc"
                # (6 unchanged attributes hidden)
            }
          + rule {
              + destination_addresses = [
                  + "10.40.40.40/32",
                ]
              + destination_ports     = [
                  + "443",
                ]
              + name                  = "ddd"
              + protocols             = [
                  + "TCP",
                ]
              + source_addresses      = [
                  + "10.10.10.10/32",
                ]
            }

            # (1 unchanged block hidden)
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

Expected Behaviour

Adding a new rule in any of the rule collections should only add the rule.

Actual Behaviour

It seems terraform deleting all the existing rules then recreating them along with the new ones

Steps to Reproduce

No response

Important Factoids

No response

References

https://github.com/hashicorp/terraform-provider-azurerm/issues/10083

shlomimn commented 1 year ago

I have added rule bbb, and the result is seen above.

"bbb" = { source_addresses = ["10.10.10.10/32"] destination_ports = ["443"] destination_addresses = ["10.21.21.21/32"] protocols = ["TCP"] }

wuxu92 commented 1 year ago

@shlomimn thanks for filing this issue. This should be a by-design as the rule is a List insteaf of Set. could you add the bbb to the end of the rules list? I believe that won't recreating the existing rules. Insert an element into a List would update all elements after it.

Tim-herbie commented 7 months ago

@wuxu92 Yes, that is right. But if you want to change an already existing rule, you get the same problem.

Because of this we can´t use Terraform right now for the azure firewall policy deployment. We maintain the firewall policies in the Azure Portal.

@catriona-m Is there maybe a workaround for this or a timeline when it will be fixed?

Tim-herbie commented 7 months ago

Workaround:

Use the azurerm_resource_group_template_deployment resource instead of azurerm_firewall_policy_rule_collection_group for the rule-collection deployment.

Example

provider "azurerm" {
  features {}
}

data "azurerm_resource_group" "rg" {
  name = "<Your-RG>"
}

resource "azurerm_resource_group_template_deployment" "example2" {
  name                = "firewall-rulecollectiongroup"
  resource_group_name = data.azurerm_resource_group.rg.name
  deployment_mode     = "Incremental"
  template_content = jsonencode({
    "$schema" : "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion" : "1.0.0.0",
    "resources" : [
      {
        "type" : "Microsoft.Network/firewallPolicies",
        "apiVersion" : "2022-01-01",
        "name" : "firewall-policy-test",
        "location" : "West Europe",
        "properties" : {
          "threatIntelMode" : "Alert"
        }
      },
      {
        "type" : "Microsoft.Network/firewallPolicies/ruleCollectionGroups",
        "apiVersion" : "2023-04-01",
        "name" : "firewall-policy-test/fwrulecollectiontype1",
        "properties" : {
          "priority" : "100",
          "ruleCollections" : [
            {
              "name" : "test1",
              "priority" : "100",
              "ruleCollectionType" : "FirewallPolicyFilterRuleCollection"
                "action" : {
                  "type" : "Allow"
                },
                "rules" : [
                  {
                    "ruleType" : "NetworkRule",
                    "name" : "rule0",
                    "ipProtocols" : [
                      "UDP"
                    ],
                    "destinationAddresses" : [
                      "13.86.101.172"
                    ],
                    "sourceAddresses" : [
                       "13.86.101.172"
                    ],
                    "destinationPorts" : [
                      "123"
                    ]
                  },
                  {
                    "ruleType" : "NetworkRule",
                    "name" : "rule1",
                    "ipProtocols" : [
                      "UDP"
                    ],
                    "destinationAddresses" : [
                      "13.86.101.172"
                    ],
                    "sourceAddresses" : [
                       "13.86.101.172"
                    ],
                    "destinationPorts" : [
                      "123"
                    ]
                  },
              {
                "ruleType" : "NetworkRule",
                "name" : "rule3",
                "ipProtocols" : [
                  "UDP"
                ],
                "destinationAddresses" : [
                  "13.86.101.172"
                ],
                "sourceAddresses" : [
                   "13.86.101.172"
                ],
                "destinationPorts" : [
                  "123"
                ]
              },
              {
                "ruleType" : "NetworkRule",
                "name" : "rule2",
                "ipProtocols" : [
                  "UDP"
                ],
                "destinationAddresses" : [
                  "13.86.101.172"
                ],
                "sourceAddresses" : [
                   "13.86.101.172"
                ],
                "destinationPorts" : [
                  "123"
                ]
              }
              ]
            }
          ]
        }
        "dependsOn" : [
          "[resourceId('Microsoft.Network/firewallPolicies', 'firewall-policy-test)]"
        ],
      }
    ]
  })
}

Here you see only the changes that you have done. If you delete a rule between two existing rules, only the rule that you would like to delete will be highlighted to delete. In this example, I removed the rule3:

Change

Terraform will perform the following actions:

  # azurerm_resource_group_template_deployment.example2 will be updated in-place
  ~ resource "azurerm_resource_group_template_deployment" "example2" {
        id                  = "/subscriptions/.../resourceGroups/.../providers/Microsoft.Resources/deployments/firewall-rulecollectiongroup"
        name                = "firewall-rulecollectiongroup"
        tags                = {}
      ~ template_content    = jsonencode(
          ~ {
              ~ resources      = [
                    {
                        apiVersion = "2022-01-01"
                        location   = "West Europe"
                        name       = "firewall-policy-test1"
                        properties = {
                            threatIntelMode = "Alert"
                        }
                        type       = "Microsoft.Network/firewallPolicies"
                    },
                  ~ {
                        name       = "firewall-policy-test1/fwrulecollectiontype1"
                      ~ properties = {
                          ~ ruleCollections = [
                              ~ {
                                    name               = "test1"
                                  ~ rules              = [
                                        # (1 unchanged element hidden)
                                        {
                                            destinationAddresses = [
                                                "13.86.101.172",
                                            ]
                                            destinationPorts     = [
                                                "123",
                                            ]
                                            ipProtocols          = [
                                                "UDP",
                                            ]
                                            name                 = "rule1"
                                            ruleType             = "NetworkRule"
                                            sourceAddresses      = [
                                                "13.86.101.172",
                                            ]
                                        },
                                      - {
                                          - destinationAddresses = [
                                              - "13.86.101.172",
                                            ]
                                          - destinationPorts     = [
                                              - "123",
                                            ]
                                          - ipProtocols          = [
                                              - "UDP",
                                            ]
                                          - name                 = "rule3"
                                          - ruleType             = "NetworkRule"
                                          - sourceAddresses      = [
                                              - "13.86.101.172",
                                            ]
                                        },
                                        {
                                            destinationAddresses = [
                                                "13.86.101.172",
                                            ]
                                            destinationPorts     = [
                                                "123",
                                            ]
                                            ipProtocols          = [
                                                "UDP",
                                            ]
                                            name                 = "rule2"
                                            ruleType             = "NetworkRule"
                                            sourceAddresses      = [
                                                "13.86.101.172",
                                            ]
                                        },
                                    ]
                                    # (3 unchanged attributes hidden)
                                },
                            ]
                            # (1 unchanged attribute hidden)
                        }
                        # (3 unchanged attributes hidden)
                    },
                ]
                # (2 unchanged attributes hidden)
            }
        )
        # (4 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.