Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_application_gateway rewrite_rule_set_name causes deployed instance to be always modified #15923

Closed
ronalddemneri opened this issue Mar 22, 2022 · 9 comments

Comments

@ronalddemneri
Copy link

ronalddemneri commented Mar 22, 2022

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform (and AzureRM Provider) Version

$ terraform -v
Terraform v1.1.7
on linux_amd64
+ provider registry.terraform.io/hashicorp/azuread v2.12.0
+ provider registry.terraform.io/hashicorp/azurerm v2.89.0

Affected Resource(s)

  • azurerm_application_gateway

Terraform Configuration Files

...
...
dynamic "request_routing_rule" {
    for_each = var.appgw_routings # map(string)
    content {
      name                        = lookup(request_routing_rule.value, "name", null)
      rule_type                   = lookup(request_routing_rule.value, "rule_type", "Basic")
      http_listener_name          = lookup(request_routing_rule.value, "http_listener_name", lookup(request_routing_rule.value, "name", null))
      backend_address_pool_name   = lookup(request_routing_rule.value, "backend_address_pool_name", null)
      backend_http_settings_name  = lookup(request_routing_rule.value, "backend_http_settings_name", null)
      url_path_map_name           = lookup(request_routing_rule.value, "url_path_map_name", null)
      redirect_configuration_name = lookup(request_routing_rule.value, "redirect_configuration_name", null)
      rewrite_rule_set_name       = lookup(request_routing_rule.value, "rewrite_rule_set_name", null)
    }
  }
...
dynamic "rewrite_rule_set" {
    for_each = var.appgw_rewrite_rule_sets
    iterator = rset
    content {
      name = lookup(rset.value, "name")

      dynamic "rewrite_rule" {
        for_each = rset.value.rewrite_rules
        iterator = rule
        content {
          name          = lookup(rule.value, "name", format("%s-%s", lookup(rset.value, "name"), lookup(rule.value, "sequence")))
          rule_sequence = lookup(rule.value, "sequence", 100)
          condition {
            pattern     = lookup(rule.value, "pattern", "")
            variable    = lookup(rule.value, "variable", "")
            negate      = lookup(rule.value, "negate", false)
            ignore_case = lookup(rule.value, "ignore_case", true)
          }
          dynamic "url" {
            for_each = lookup(rule.value, "path", null) != null ? ["dummy"] : []
            content {
              path         = lookup(rule.value, "path")
              query_string = lookup(rule.value, "query_string", "")
              reroute      = lookup(rule.value, "reroute", false)
            }
          }
          dynamic "request_header_configuration" {
            for_each = lookup(rule.value, "req_header_name", null) != null ? ["dummy"] : []
            content {
              header_name  = lookup(rule.value, "req_header_name", "")
              header_value = lookup(rule.value, "req_header_value", "")
            }
          }
          dynamic "response_header_configuration" {
            for_each = lookup(rule.value, "res_header_name", null) != null ? ["dummy"] : []
            content {
              header_name  = lookup(rule.value, "res_header_name", "")
              header_value = lookup(rule.value, "res_header_value", "")
            }
          }
        }
      }
    }
  }
...

Debug Output

Panic Output

Expected Behaviour

After already applying the Terraform code as a result of adding the name of the rewrite_rule_set in the request_routing_rule configuration, I expect that terraform plan will not prompt for the resource to be updated again (and again).

Actual Behaviour

My code is very similar to #8397, except that I am using dynamic blocks. The rewrite_rule_set variable is a list of objects, as follows:

variable "appgw_rewrite_rule_sets" {
  type        = list(object({
    name            = string
    rewrite_rules   = list(object({
      name             = string
      sequence         = number
      pattern          = string
      variable         = string
      negate           = bool
      ignore_case      = bool
      path             = string
      query_string     = string
      reroute          = bool
      req_header_name  = string
      req_header_value = string
      res_header_name  = string
      res_header_value = string
    }))
  }))
  description = "Nested map of objects containing the rewrite rules to be applied to the Application Gateway http request rules."
}

What happens is that, regardless how many times I run terraform apply, terraform plan will always return that there are changes to be made. As for the aforementioned issue #8397, I get the rewrite_rule_set_id, but not the rewrite_rule_set_name. I have three environments that are all affected by this issue (providing a short snippet below). As for #8397, the request_routing_rule is dissociated from the rewrite_rule_set, but I can still link these together via the portal; the problem is that when applying again, the association will be removed over and over.

{
...
      - request_routing_rule {
          - backend_address_pool_id    = "/subscriptions/.../gateway-prds-1-2-3/backendAddressPools/be-pool-prd" -> null
          - backend_address_pool_name  = "be-pool-prd" -> null
          - backend_http_settings_id   = "/subscriptions/.../gateway-prds-1-2-3/backendHttpSettingsCollection/be-setting-http-80" -> null
          - backend_http_settings_name = "be-setting-http-80" -> null
          - http_listener_id           = "/subscriptions/.../gateway-prds-1-2-3/httpListeners/https-listener" -> null
          - http_listener_name         = "https-listener" -> null
          - id                         = "/subscriptions/.../gateway-prds-1-2-3/requestRoutingRules/routing-rule" -> null
          - name                       = "routing-rule" -> null
          - priority                   = 0 -> null
          - rewrite_rule_set_id        = "/subscriptions/.../gateway-prds-1-2-3/rewriteRuleSets/rewrite-set-001" -> null
          - rewrite_rule_set_name      = "rewrite-set-001" -> null
          - rule_type                  = "Basic" -> null
        }
      + request_routing_rule {
          + backend_address_pool_id    = (known after apply)
          + backend_address_pool_name  = "be-pool-prd"
          + backend_http_settings_id   = (known after apply)
          + backend_http_settings_name = "be-setting-http-80"
          + http_listener_id           = (known after apply)
          + http_listener_name         = "https-listener"
          + id                         = (known after apply)
          + name                       = "routing-rule"
          + redirect_configuration_id  = (known after apply)
          + rewrite_rule_set_id        = (known after apply)
          + rule_type                  = "Basic"
          + url_path_map_id            = (known after apply)
        }

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

Initially, I thought the problem was because I declared the rewrite_rule_set variable as a set(object{...})), but I changed it to list(object({...})) so that to keep my ordering, but it still persists.

Steps to Reproduce

Noting special to reproduce, terraform apply, then terraform plan, and you can see that the request routing rule will always be modified.

  1. terraform apply
  2. terraform plan

Important Factoids

References

  • #0000
@neil-yechenwei
Copy link
Contributor

neil-yechenwei commented Mar 23, 2022

@ronalddemneri , thanks for raising this issue. Seem I cannot repro this issue on my local with latest azurerm provider and below repro steps. If it's possible, you can try my below tf config to see if the issue still exists. May I ask how many request_routing_rule blocks and rewrite_rule_set blocks you defined in your tf config file while not using dynamic? Could you share the simplest tf config that triggers this issue? And could you double confirm whether below repro steps are expected? Thanks in advance.

Repro steps:

  1. First apply without request_routing_rule.rewrite_rule_set_name and rewrite_rule_set:
provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "test" {
  name     = "acctestRG-appgw-test01"
  location = "West Europe"
}

resource "azurerm_virtual_network" "test" {
  name                = "acctest-vnet-test01"
  resource_group_name = azurerm_resource_group.test.name
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.test.location
}

resource "azurerm_subnet" "test" {
  name                                          = "subnet-test01"
  resource_group_name                           = azurerm_resource_group.test.name
  virtual_network_name                          = azurerm_virtual_network.test.name
  address_prefix                                = "10.0.0.0/24"
  enforce_private_link_service_network_policies = true
}

resource "azurerm_public_ip" "test" {
  name                = "acctest-pubip-test01"
  location            = azurerm_resource_group.test.location
  resource_group_name = azurerm_resource_group.test.name
  allocation_method   = "Dynamic"
}

# since these variables are re-used - a locals block makes this more maintainable
locals {
  backend_address_pool_name      = "${azurerm_virtual_network.test.name}-beap"
  frontend_port_name             = "${azurerm_virtual_network.test.name}-feport"
  frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip"
  http_setting_name              = "${azurerm_virtual_network.test.name}-be-htst"
  listener_name                  = "${azurerm_virtual_network.test.name}-httplstn"
  request_routing_rule_name      = "${azurerm_virtual_network.test.name}-rqrt"
  rewrite_rule_set_name          = "${azurerm_virtual_network.test.name}-rwset"
  rewrite_rule_name              = "${azurerm_virtual_network.test.name}-rwrule"
}

resource "azurerm_public_ip" "test_standard" {
  name                = "acctest-pubip-test01-standard"
  location            = azurerm_resource_group.test.location
  resource_group_name = azurerm_resource_group.test.name
  sku                 = "Standard"
  allocation_method   = "Static"
}

resource "azurerm_application_gateway" "test" {
  name                = "acctestag-test01"
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location

  sku {
    name     = "Standard_v2"
    tier     = "Standard_v2"
    capacity = 2
  }

  gateway_ip_configuration {
    name      = "my-gateway-ip-configuration"
    subnet_id = azurerm_subnet.test.id
  }

  frontend_port {
    name = local.frontend_port_name
    port = 80
  }

  frontend_ip_configuration {
    name                 = local.frontend_ip_configuration_name
    public_ip_address_id = azurerm_public_ip.test_standard.id
  }

  backend_address_pool {
    name  = local.backend_address_pool_name
    fqdns = ["foo.com", "bar.com"]
  }

  backend_http_settings {
    name                  = local.http_setting_name
    cookie_based_affinity = "Disabled"
    port                  = 80
    protocol              = "Http"
    request_timeout       = 1
  }

  http_listener {
    name                           = local.listener_name
    frontend_ip_configuration_name = local.frontend_ip_configuration_name
    frontend_port_name             = local.frontend_port_name
    protocol                       = "Http"
  }

  request_routing_rule {
    name                       = local.request_routing_rule_name
    rule_type                  = "Basic"
    http_listener_name         = local.listener_name
    backend_address_pool_name  = local.backend_address_pool_name
    backend_http_settings_name = local.http_setting_name
  }
}
  1. Until now, tf plan doesn't show any diff.

  2. Add request_routing_rule.rewrite_rule_set_name and rewrite_rule_set for azurerm_application_gateway and perform second apply:

resource "azurerm_application_gateway" "test" {
  name                = "acctestag-test01"
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location

  sku {
    name     = "Standard_v2"
    tier     = "Standard_v2"
    capacity = 2
  }

  gateway_ip_configuration {
    name      = "my-gateway-ip-configuration"
    subnet_id = azurerm_subnet.test.id
  }

  frontend_port {
    name = local.frontend_port_name
    port = 80
  }

  frontend_ip_configuration {
    name                 = local.frontend_ip_configuration_name
    public_ip_address_id = azurerm_public_ip.test_standard.id
  }

  backend_address_pool {
    name  = local.backend_address_pool_name
    fqdns = ["foo.com", "bar.com"]
  }

  backend_http_settings {
    name                  = local.http_setting_name
    cookie_based_affinity = "Disabled"
    port                  = 80
    protocol              = "Http"
    request_timeout       = 1
  }

  http_listener {
    name                           = local.listener_name
    frontend_ip_configuration_name = local.frontend_ip_configuration_name
    frontend_port_name             = local.frontend_port_name
    protocol                       = "Http"
  }

  request_routing_rule {
    name                       = local.request_routing_rule_name
    rule_type                  = "Basic"
    http_listener_name         = local.listener_name
    backend_address_pool_name  = local.backend_address_pool_name
    backend_http_settings_name = local.http_setting_name
    rewrite_rule_set_name      = local.rewrite_rule_set_name
  }

  rewrite_rule_set {
    name = local.rewrite_rule_set_name

    rewrite_rule {
      name          = local.rewrite_rule_name
      rule_sequence = 1

      condition {
        variable = "var_http_status"
        pattern  = "502"
      }

      request_header_configuration {
        header_name  = "X-custom"
        header_value = "customvalue"
      }
    }
  }
}
  1. Until now, tf plan doesn't show any diff.

@ronalddemneri
Copy link
Author

Hello @neil-yechenwei,

Thanks for having a look. to be honest I only tested this with dynamic blocks. I have a single request_routing_rule and a single rewrite_rule_set with four rewrite_rule(s).

I will try your suggestion and post back the results.

@ronalddemneri
Copy link
Author

This is the actual code that I am using:

# main.tf
resource "azurerm_application_gateway" "appgw" {
  location            = var.appgw_location       # string
  name                = var.appgw_name           # string
  resource_group_name = var.appgw_resource_group # string
  zones               = var.appgw_av_zones       # list(number)
  tags                = var.tags                 # map(string)

  sku {
    name     = var.appgw_sku_name                                                     # string
    tier     = var.appgw_sku_tier                                                     # string
    capacity = var.appgw_sku_capacity                                                 # number
  }

  dynamic "autoscale_configuration" {
    for_each = tostring(var.appgw_sku_capacity) == "0" ? ["dummy"] : []
    content {
      min_capacity = tostring(var.appgw_sku_capacity) == "0" ? lookup(var.appgw_autoscale_params, "appgw_autoscale_min") : null        # number
      max_capacity = tostring(var.appgw_sku_capacity) == "0" ? lookup(var.appgw_autoscale_params, "appgw_autoscale_max") : null        # number
    }
  }

  # Public IP address for the v2 SKU
  frontend_ip_configuration {
    name                 = var.appgw_frontend_ip_configuration_name
    public_ip_address_id = var.appgw_public_ip_address_id
  }

  dynamic "frontend_ip_configuration" {
    for_each = var.appgw_private ? ["dummy"] : []
    content {
      name                          = var.appgw_private ? var.appgw_frontend_priv_ip_configuration_name : null
      private_ip_address_allocation = var.appgw_private ? "Static" : null
      private_ip_address            = var.appgw_private ? var.appgw_private_ip : null
      subnet_id                     = var.appgw_private ? var.appgw_subnet_id : null
    }
  }

  dynamic "frontend_port" {
    for_each = var.appgw_fe_port # list(object)
    content {
      name = lookup(frontend_port.value, "name", null) # string
      port = lookup(frontend_port.value, "port", null) # number
    }
  }

  gateway_ip_configuration {
    name      = var.appgw_gw_ip_config_name # string
    subnet_id = var.appgw_subnet_id   # string
  }

  # For v2 SKUs; v1 SKUs uses authentication_certificate
  dynamic "trusted_root_certificate" {
    for_each = var.trusted_root_certificate_configs
    content {
      name = lookup(trusted_root_certificate.value, "name", null)
      # use filename if supplied, otherwise use data
      data = lookup(trusted_root_certificate.value, "data", null) == null ? filebase64(lookup(trusted_root_certificate.value, "filename", null)) : lookup(trusted_root_certificate.value, "data", null)
    }
  }

  dynamic "probe" {
    for_each = var.appgw_probes # list(object)
    content {
      host                                      = lookup(probe.value, "host", null)
      interval                                  = lookup(probe.value, "interval", 30)
      name                                      = lookup(probe.value, "name", null)
      path                                      = lookup(probe.value, "path", "/")
      port                                      = lookup(probe.value, "port", 80)
      protocol                                  = lookup(probe.value, "protocol", "Https")
      timeout                                   = lookup(probe.value, "timeout", 30)
      pick_host_name_from_backend_http_settings = lookup(probe.value, "pick_host_name_from_backend_http_settings", false)
      unhealthy_threshold                       = lookup(probe.value, "unhealthy_threshold", 3)
      match {
        body        = lookup(probe.value, "match_body", "")
        status_code = lookup(probe.value, "match_status_code", ["200-399"])
      }
    }
  }

  dynamic "backend_address_pool" {
    for_each = var.appgw_be_address_pools
    content {
      name         = lookup(backend_address_pool.value, "name", null)         # string
      ip_addresses = length(lookup(backend_address_pool.value, "ip_addresses")) > 0 ? lookup(backend_address_pool.value, "ip_addresses") : null # list(string)
      fqdns        = length(lookup(backend_address_pool.value, "fqdns")) > 0 ? lookup(backend_address_pool.value, "fqdns") : null  # list(string)
    }
  }

  dynamic "backend_http_settings" {
    for_each = var.appgw_backend_http_settings
    content {
      name       = lookup(backend_http_settings.value, "name", null)
      path       = lookup(backend_http_settings.value, "path", "")
      probe_name = lookup(backend_http_settings.value, "probe_name", null)

      affinity_cookie_name                = lookup(backend_http_settings.value, "affinity_cookie_name", "ApplicationGatewayAffinity")
      cookie_based_affinity               = lookup(backend_http_settings.value, "cookie_based_affinity", "Disabled")
      pick_host_name_from_backend_address = lookup(backend_http_settings.value, "pick_host_name_from_backend_address", true)
      host_name                           = lookup(backend_http_settings.value, "host_name", null)
      port                                = lookup(backend_http_settings.value, "port", 443)
      protocol                            = lookup(backend_http_settings.value, "protocol", "Https")
      request_timeout                     = lookup(backend_http_settings.value, "request_timeout", 20)
      trusted_root_certificate_names      = lookup(backend_http_settings.value, "trusted_root_certificate_names", [])
    }
  }

  dynamic "ssl_certificate" {
    for_each = var.appgw_ssl_certificates # list(map(string))
    content {
      name                = ssl_certificate.value.name
      key_vault_secret_id = ssl_certificate.value.key_vault_secret_id
    }
  }

  dynamic "http_listener" {
    for_each = var.appgw_http_listeners # list(object{})
    content {
      name                           = lookup(http_listener.value, "name", null)
      frontend_ip_configuration_name = lookup(http_listener.value, "frontend_ip_conf", var.appgw_private ? var.appgw_frontend_priv_ip_configuration_name : var.appgw_frontend_ip_configuration_name)
      frontend_port_name             = lookup(http_listener.value, "frontend_port_name", null)
      protocol                       = lookup(http_listener.value, "protocol", "Https")
      ssl_certificate_name           = lookup(http_listener.value, "ssl_certificate_name", null)
      host_name                      = lookup(http_listener.value, "host_name", null)
      host_names                     = lookup(http_listener.value, "host_names", [])
      require_sni                    = lookup(http_listener.value, "require_sni", null)
      firewall_policy_id             = lookup(http_listener.value, "firewall_policy_id", null)
      ssl_profile_name               = lookup(http_listener.value, "ssl_profile_name", null)
    }
  }

  dynamic "request_routing_rule" {
    for_each = var.appgw_routings # map(string)
    content {
      name                        = lookup(request_routing_rule.value, "name", null)
      rule_type                   = lookup(request_routing_rule.value, "rule_type", "Basic")
      http_listener_name          = lookup(request_routing_rule.value, "http_listener_name", lookup(request_routing_rule.value, "name", null))
      backend_address_pool_name   = lookup(request_routing_rule.value, "backend_address_pool_name", null)
      backend_http_settings_name  = lookup(request_routing_rule.value, "backend_http_settings_name", null)
      url_path_map_name           = lookup(request_routing_rule.value, "url_path_map_name", null)
      redirect_configuration_name = lookup(request_routing_rule.value, "redirect_configuration_name", null)
      rewrite_rule_set_name       = lookup(request_routing_rule.value, "rewrite_rule_set_name", null)
    }
  }

  dynamic "rewrite_rule_set" {
    for_each = var.appgw_rewrite_rule_sets
    iterator = rset
    content {
      name = lookup(rset.value, "name")

      dynamic "rewrite_rule" {
        for_each = rset.value.rewrite_rules
        iterator = rule
        content {
          name          = lookup(rule.value, "name", format("%s-%s", lookup(rset.value, "name"), lookup(rule.value, "sequence")))
          rule_sequence = lookup(rule.value, "sequence", 100)
          condition {
            pattern     = lookup(rule.value, "pattern", "")
            variable    = lookup(rule.value, "variable", "")
            negate      = lookup(rule.value, "negate", false)
            ignore_case = lookup(rule.value, "ignore_case", true)
          }
          dynamic "url" {
            for_each = lookup(rule.value, "path", null) != null ? ["dummy"] : []
            content {
              path         = lookup(rule.value, "path")
              query_string = lookup(rule.value, "query_string", "")
              reroute      = lookup(rule.value, "reroute", false)
            }
          }
          dynamic "request_header_configuration" {
            for_each = lookup(rule.value, "req_header_name", null) != null ? ["dummy"] : []
            content {
              header_name  = lookup(rule.value, "req_header_name", "")
              header_value = lookup(rule.value, "req_header_value", "")
            }
          }
          dynamic "response_header_configuration" {
            for_each = lookup(rule.value, "res_header_name", null) != null ? ["dummy"] : []
            content {
              header_name  = lookup(rule.value, "res_header_name", "")
              header_value = lookup(rule.value, "res_header_value", "")
            }
          }
        }
      }
    }
  }

  ssl_policy {
    policy_type = "Custom"
    cipher_suites = var.appgw_ssl_cipher_suites
    min_protocol_version = "TLSv1_2"
    #    policy_name = "CustomSSLPolicy"
  }

  dynamic "ssl_profile" {
    for_each = var.appgw_ssl_profiles
    content {
      name                             = lookup(ssl_profile.value, "name", null)
      verify_client_cert_issuer_dn     = lookup(ssl_profile.value, "verify_client_issuer_dn", false)
      trusted_client_certificate_names = lookup(ssl_profile.value, "trusted_client_cert_names", [])
      ssl_policy {
        policy_type = "Custom"
        cipher_suites = var.appgw_ssl_cipher_suites
        min_protocol_version = "TLSv1_2"
        #        policy_name = "CustomSSLPolicy"
      }
    }
  }

  identity {
    identity_ids = var.appgw_identity_ids  # list(string)
    type         = var.appgw_identity_type # list (eg. UserAssigned)
  }
}

# variables.tf
variable "appgw_sku_capacity" {
  type        = number
  description = "Number of Application Gateway instances to deploy, in case Autoscaling is not enabled. Mutually exclusive with Autoscaling."
}
variable "appgw_sku_tier" {
  type        = string
  description = "SKU tier of the Application Gateway. Possible values are \"Standard\", \"WAF\", \"Standard_v2\" and \"WAF_v2\"."
}
variable "appgw_sku_name" {
  type        = string
  description = "SKU tier of the Application Gateway. Possible values are \"Standard\", \"WAF\", \"Standard_v2\" and \"WAF_v2\"."
}

variable "appgw_gw_ip_subnet_id" {
  type        = string
  description = "The ID of the Subnet which the Application Gateway should be connected to."
}

variable "appgw_gw_ip_config_name" {
  type        = string
  description = " The Name of this Gateway IP Configuration."
}

variable "appgw_fe_port" {
  type        = list(object({
    name = string,
    port = number
  }))
  description = "List of objects containing the configuration of the frontend ports for the Application Gateway."
}

variable "appgw_be_address_pools" {
  type        = list(object({
    name         = string
    ip_addresses = list(string)
    fqdns        = list(string)
  }))
  description = "List of objects containing the configuration settings for the backend pool(s) of the Application Gateway."
}

variable "appgw_probes" {
  type = list(object({
    host                                      = string,
    interval                                  = number, # Default 30
    name                                      = string,
    path                                      = string, # Default '/'
    protocol                                  = string, # Default Https
    pick_host_name_from_backend_http_settings = bool,   # Default false
    timeout                                   = number, # Default 30
    unhealthy_threshold                       = number  # Default 3
    match_body                                = string
    match_status_code                         = list(string) # Default ["200-399"]
  }))
  description = "List of objects containing the configuration of the health probes for the backend pool(s) of the Application Gateway."
}

variable "appgw_autoscale_params" {
  type    = map(number)
  description = "Map of key/value pairs for configuring the Autoscaling functionality of Application Gateway. Should contain at least a key named \"appgw_capacity_min\"."
}

variable "tags" {
  type    = map(string)
  description = "Map of strings for applying tags to deployed resources."
}

variable "appgw_av_zones" {
  type    = list(string)
  description = "List of the AV zones where the Application Gateway should be deployed (for enabling zone HA)."
}

variable "appgw_resource_group" {
  type    = string
  description = "Name of the resource group where the Applicaiton Gateway will be deployed."
}

variable "appgw_name" {
  type    = string
  description = "Name of the Application Gateway."
}

variable "appgw_location" {
  type    = string
  description = "Location where to deploy the Application Gateway."
}

variable "trusted_root_certificate_configs" {
  type = list(map(string))
  #      name      = string
  #      data      = string
  #      filename  = string
  # }))
  description = "List of trusted root certificates. The needed values for each trusted root certificates are 'name' and 'data' or 'filename'. This parameter is required if you are not using a trusted certificate authority (eg. selfsigned certificate)"
}


variable "appgw_private" {
  type    = bool
  description = "Variable commanding the creation of the Private IP address for v2 SKUs of Application Gateway."
}

variable "appgw_frontend_priv_ip_configuration_name" {
  type    = string
  description = "Application Gateway configuration name for the private IP address."
}

variable "appgw_frontend_ip_configuration_name" {
  type    = string
  description = "Application Gateway configuration name for the public IP address."
}

variable "appgw_private_ip" {
  type    = string
  description = "Private IP address assigned to the Application Gateway, when \"appgw_private\" is set to \"true\"."
}

variable "appgw_subnet_id" {
  type    = string
  description = "Subnet id where the Application Gateway will be connected."
}

variable "appgw_backend_http_settings" {
  type = list(object({
    name                                = string
    path                                = string
    probe_name                          = string
    affinity_cookie_name                = string
    cookie_based_affinity               = string # Enabled/Disabled
    pick_host_name_from_backend_address = bool
    host_name                           = string
    port                                = number # Default 443
    protocol                            = string
    request_timeout                     = number
    trusted_root_certificate_names      = list(string)
  }))
  description = "List of objects containing the configuration of the backend HTTP settings for the Application Gateway."
}

variable "appgw_http_listeners" {
  type = list(object({
    name                 = string
    frontend_ip_conf     = string
    frontend_port_name   = string
    protocol             = string
    ssl_certificate_name = string
    host_name            = string
    host_names           = set(string)
    require_sni          = bool
    firewall_policy_id   = string
    ssl_profile_name     = string
  }))
  description = "List of objects containing the configuration of the HTTP listeners settings for the Application Gateway."
}


variable "appgw_routings" {
  type    = list(map(string))
  /*default = [{
      name                         = ""
      rule_type                    = ""
      http_listener_name           = ""
      backend_address_pool_name    = ""
      backend_http_settings_name   = ""
      url_path_map_name            = ""
      redirect_configuration_name  = ""
      rewrite_rule_set_name        = ""
     }]*/
  description = "List of maps containing the configuration of request routings for the Application Gateway."
}

variable "appgw_rewrite_rule_sets" {
  type        = list(object({
    name            = string
    rewrite_rules   = list(object({
      name             = string
      sequence         = number
      pattern          = string
      variable         = string
      negate           = bool
      ignore_case      = bool
      path             = string
      query_string     = string
      reroute          = bool
      req_header_name  = string
      req_header_value = string
      res_header_name  = string
      res_header_value = string
    }))
  }))
  description = "Nested map of objects containing the rewrite rules to be applied to the Application Gateway http request rules."
}

variable "appgw_identity_ids" {
  type    = list(string)
  description = "List of the Object IDs of Security Principals that are used on the Application Gateway to read secrets, keys and certificates from an Azure Key Vault."
}

variable "appgw_identity_type" {
  type    = string
  default = "UserAssigned"
  description = "Type of the Managed Identity. Possible values are \"SystemAssigned\" and \"UserAssigned\", where the latter is the default setting."
}

variable "appgw_ssl_certificates" {
  type        = list(map(string))
  description = "List of name/key_vault_secret_id for each certificate"
}

variable "appgw_ssl_profiles" {
  type = list(object({
    name                      = string
    verify_client_issuer_dn   = bool
    trusted_client_cert_names = list(string)
  }))
  description = "List of objects containing the configurations of SSL profiles to assign to the Application Gateway."
}

variable "appgw_ssl_cipher_suites" {
  type = list(string)
  default = [
      "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
      "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
    ]
    description = "List of the default SSL cipher suites that need to be assigned to the Application Gateway (eg. for deprecating TLS1.0)."
}

variable "appgw_public_ip_address_id" {
  type = string
  description = "Public IP address ID assigned to the Application Gateway. Required for v2 SKUs."
#  default = null
}

@tombuildsstuff
Copy link
Contributor

Duplicate of #6896 which is fixed by #15800, coming in 3.0

@ronalddemneri
Copy link
Author

Hello @tombuildsstuff,

I am not sure if this is actually related to #6896 or any of the other issues referenced by #15800. But I will try to use the 3.0 provider and see how it works out.

Regards,
Ronald

@ronalddemneri
Copy link
Author

ronalddemneri commented Mar 23, 2022

Hello @tombuildsstuff,

I can confirm that when using the azurerm 3.0-beta provider, tf plan does indeed show that the state matches the configuration. But I still have the request_routing_rule dissociated with the rewrite_rule_set:

Partial output from
terraform state show module.application_gateway_secured.module.app_gateway.azurerm_application_gateway.appgw

...
...
    request_routing_rule {
        backend_address_pool_id    = "/subscriptions/.../gateway-devs-1/backendAddressPools/be-pool-dev"
        backend_address_pool_name  = "be-pool-dev"
        backend_http_settings_id   = "/subscriptions/../gateway-devs-1/backendHttpSettingsCollection/be-setting-http-80"
        backend_http_settings_name = "be-setting-http-80"
        http_listener_id           = "/subscriptions/.../-gateway-devs-1/httpListeners/https-listener"
        http_listener_name         = "https-listener"
        id                         = "/subscriptions/.../gateway-devs-1/requestRoutingRules/routing-rule"
        name                       = "routing-rule"
        priority                   = 0
        rule_type                  = "Basic"
    }

    rewrite_rule_set {
        id   = "/subscriptions/.../gateway-devs-1/rewriteRuleSets/rewrite-set-001"
        name = "rewrite-set-001"

        rewrite_rule {
            name          = "RewritePath"
            rule_sequence = 100

            condition {
                ignore_case = true
                negate      = false
                pattern     = "<some pattern>"
                variable    = "var_uri_path"
            }
...
...

Any idea how to fix this (which in fact is the main reason I created this bug)?

@ronalddemneri
Copy link
Author

Do you think I need to open a new issue #

Hello @tombuildsstuff,

I can confirm that when using the azurerm 3.0-beta provider, tf plan does indeed show that the state matches the configuration. But I still have the request_routing_rule dissociated with the rewrite_rule_set:

Partial output from terraform state show module.application_gateway_secured.module.app_gateway.azurerm_application_gateway.appgw

...
...
    request_routing_rule {
        backend_address_pool_id    = "/subscriptions/.../gateway-devs-1/backendAddressPools/be-pool-dev"
        backend_address_pool_name  = "be-pool-dev"
        backend_http_settings_id   = "/subscriptions/../gateway-devs-1/backendHttpSettingsCollection/be-setting-http-80"
        backend_http_settings_name = "be-setting-http-80"
        http_listener_id           = "/subscriptions/.../-gateway-devs-1/httpListeners/https-listener"
        http_listener_name         = "https-listener"
        id                         = "/subscriptions/.../gateway-devs-1/requestRoutingRules/routing-rule"
        name                       = "routing-rule"
        priority                   = 0
        rule_type                  = "Basic"
    }

    rewrite_rule_set {
        id   = "/subscriptions/.../gateway-devs-1/rewriteRuleSets/rewrite-set-001"
        name = "rewrite-set-001"

        rewrite_rule {
            name          = "RewritePath"
            rule_sequence = 100

            condition {
                ignore_case = true
                negate      = false
                pattern     = "<some pattern>"
                variable    = "var_uri_path"
            }
...
...

Any idea how to fix this (which in fact is the main reason I created this bug)?

Do you think I need to open a new issues for this?

@ronalddemneri ronalddemneri changed the title azurerm_application_gateway rewrite_rule_set_name is causes deployed instance to be always modified azurerm_application_gateway rewrite_rule_set_name causes deployed instance to be always modified Mar 23, 2022
@github-actions
Copy link

This functionality has been released in v3.0.0 of the Terraform Provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you!

@github-actions
Copy link

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants