hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager

Home Page:https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

azurerm_app_service ip_restriction doesn't remove subnet_id when unset

martinjt opened this issue Β· comments

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 v0.12.28
  • provider.azurerm v2.30.0

Affected Resource(s)

  • azurerm_app_service

Terraform Configuration Files

before

resource "azurerm_app_service" "app" {
  ...
  site_config {
    
    ip_restriction {
      ip_address                = null
      priority                  = 1000
      name                      = "InternalAppSubnet"
      action                    = "Allow"
      virtual_network_subnet_id = azurerm_subnet.app.id
      subnet_id                 = azurerm_subnet.app.id
    }
}

After

resource "azurerm_app_service" "app" {
  ...
  site_config {
    
    ip_restriction {
      ip_address                = 10.0.0.0/8
      priority                  = 1000
      name                      = "InternalAppSubnet"
      action                    = "Allow"
      virtual_network_subnet_id = null
      subnet_id                 = null
    }
}

Debug Output

Debug Output

Panic Output

Expected Behavior

When switching from using subnet's to IP addresses, the subnet should be blanked. This is more of an issue if the ip_restriction block is part of a dynamic nested block, as removing an item in the middle of the list will cause the plan to think it's changing them in sequence.

Actual Behavior

The plan tries to add the IP address is added to the existing restriction, but the subnet is not removed. This causes a failure as only 1 of the 2 can be set at a time.

Steps to Reproduce

  1. Plan and Apply the "before" block into Azure, so you have a subnet added as an IP restriction.
  2. Change the block to the "after" block
  3. Plan and Apply again.

Important Factoids

The above usecase is a minimal replication, the most common usecase will be using a dynamic block for the IP restrictions which is far more likely to cause the issue.

References

  • #0000
commented

To solve this temporarily, I added a 'buffer' in the ip_restrictions list between the ip_address restrictions and the subnet restrictions. This way, when I add a new ip_address restriction, an element from my 'buffer' gets removed and the subnet restrictions don't change position in the array:

My ip address restriction

  ip_restriction_ip_whitelist = [for v in var.ip_whitelist : {
    name                      = "Terraform IP whitelist"
    ip_address                = k
    priority                  = 1000
    action                    = "Allow"
    subnet_id                 = null
    virtual_network_subnet_id = null
  }]

My subnet restriction

  ip_restriction_subnets = [for v in var.whitelisted_subnets : {
    virtual_network_subnet_id = v
    action                    = "Allow"
    name                      = "Terraform Subnet whitelist"
    priority                  = 2000
    ip_address                = null
    subnet_id                 = null

  }]

My previous ip_restriction list that caused issues when adding/removing ip addresses:

ip_restriction_all = concat(local.ip_restriction_ip_whitelist, local.ip_restriction_subnets)

How I solved it:

  dummylist = [for v in range(1, 255) : {
    // Due to https://github.com/terraform-providers/terraform-provider-azurerm/issues/8768, adding an IP to the ip restriction whitelist becomes very cumbersome.
    // You will end up with elements in the array that contain both an ip_address and a subnet. Because of this, applying will generate an error.
    name                      = "dummyIP-${v}"
    ip_address                = "169.254.0.${v}/32"
    priority                  = 10000
    action                    = "Deny"
    subnet_id                 = null
    virtual_network_subnet_id = null
  }]
  ip_restriction_all = concat(local.ip_restriction_ip_whitelist, slice(local.dummylist, length(local.ip_restriction_ip_whitelist) + 1, length(local.dummylist) ), local.ip_restriction_subnets)

The solution @w0ut0 (we're colleagues) mentioned above didn't seem to work in the end :/ Another colleague of mine, @samueldumont, thinks it's because the provider sets empty strings instead of null when refreshing the state.

I myself think that the cause of this issue is the duplicate subnet property. It seems like it's not properly copying null to the other property.

@tombuildsstuff any news about this issue please ?

@tombuildsstuff would it be possible to update the provider so ip_address and virtual_network_subnet_id can take "" so these can be cleared if needed? I'm using dynamic two blocks to create ip / subnet exceptions using list variables. This error only occurs when we are updating. If I add to the end of the first list (ips - first dynamic block), terraform then tries to update the first subnet generated by the second block (subnets) but leaves the subnet ID present. When this applies it tries to create an entry with both attributes set and fails. I can't figure a way around this, nulling the attribute isn't honored either.

image

commented

@martinjt did you find a useable workaround by any chance?

Hi, I found a workaround. Combine all your restrictions into a single list and in-turn a single dynamic block for these restrictions. If you need to add new restrictions, add them as the last element in the list so you don't get this behavior. The outline code below should help. It expects a list of IP4, SubnetID, so far this has worked for me. May need some tweeks.

locals {

regex_ip4_raw = <<IP4
\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){3}\b
IP4

regex_ip4 = chomp(local.regex_ip4_raw)

}

resource "azurerm_function_app" "function_app" {

  name                       = {}
  location                   = {}
  resource_group_name        = {}
  app_service_plan_id        = {}

  site_config {

    dynamic "ip_restriction" {
      for_each = var.site_ip_restriction_ip != null ? var.site_ip_restriction_ip : [] 
        content {
          name                      = {}
          priority                  = {}
          virtual_network_subnet_id = length(regexall("/subscriptions/", ip_restriction.value)) > 0 ? ip_restriction.value : null
          ip_address                = length(regexall(local.regex_ip4, ip_restriction.value)) > 0 ? ip_restriction.value : null
        }
    }     
  } 

}

The mentioned repro does not work for us, we still have the same issue.

I built a simple repro for this, you can find the code and the needed steps in this repo: https://github.com/sdebruyn/tf-azurerm-repro-ip-restr

I can confirm this is because of a bug in this provider (see acc test in #10843). It tries to set both values at the same time.
Screenshot 2021-03-04 at 23 42 58

This has been released in version 2.56.0 of the provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading. As an example:

provider "azurerm" {
    version = "~> 2.56.0"
}
# ... other configuration ...

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 feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error πŸ€– πŸ™‰ , please reach out to my human friends πŸ‘‰ hashibot-feedback@hashicorp.com. Thanks!