0
votes

This is regarding an Azure resource, app_service, but I think it’s a more general HCL question…

You can specify IP restrictions to an app_service using a dynamic block e.g.

locals {
  ip_addresses = [ "192.168.250.1" ]
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "West Europe"
}

resource "azurerm_app_service_plan" "example" {
  name                = "example-appserviceplan"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  sku {
    tier = "Standard"
    size = "S1"
  }
}

resource "azurerm_app_service" "example" {
  name                = "example-app-service"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    dotnet_framework_version = "v4.0"
    scm_type                 = "LocalGit"
  }

  app_settings = {
    "SOME_KEY" = "some-value"
  }

  connection_string {
    name  = "Database"
    type  = "SQLServer"
    value = "Server=some-server.mydomain.com;Integrated Security=SSPI"
  }

  dynamic "ip_restriction" {
    for_each = toset(local.ip_addresses)
    content {
      ip_address = each.value
    }
  }  
}

However, to remove the restrictions you need to explicit assign ip_restriction to the empty list, i.e.

resource "azurerm_app_service" "example" {
  ...

  ip_restriction = []
}

What I don’t see is how to do this conditionally - if I make two resources and have those conditional my app_service will be created/destroyed whereas I need it updated in place.

2

2 Answers

2
votes

I'm afraid that the dynamic block does not support an empty list when using a conditional expression. Read more reference here.

After my validation, the conditional expression like for_each = var.some_variable == "" ? [] : [1] does not work when var.some_variable set to null but this could work seperately when for_each = var.some_variable and var.some_variable set to null.

So, in this case, as the answer from @rkm, you can use the for loop like this working sample for me.

variable "ip_restrictions" {

default = [
    #   {
    #   ip_address = "1.1.1.1/32"
    #   virtual_network_subnet_id = null
    #   subnet_id = null
    #   name = "aaa"
    #   priority = 110
    #   action = "Allow"
    # },

    # {
    #   ip_address = "2.2.2.2/32"
    #   virtual_network_subnet_id = null
    #   subnet_id = null
    #   name = "bbb"
    #   priority = 112
    #   action = "Allow"
    # },

]

}


resource "azurerm_app_service" "example" {
  name                = "nn-example-app-service"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {

  ip_restriction =  [

   for s in var.ip_restrictions :

   {

      ip_address = s.ip_address
      virtual_network_subnet_id = s.virtual_network_subnet_id
      subnet_id = s.subnet_id
      name = s.name
      priority = s.priority
      action = s.action

   }
  ]
}
}
1
votes

This is special terraform syntax called Attributes as Blocks. Resource arguments defined using nested block syntax implicitly define a fixed collection of objects and thus in order to specify zero objects, we should explicitly set empty list. And these two forms cannot be mixed.

With that said, terraform supports an argument syntax too (even though they recommend using block syntax for simple cases for readability):

example = [
  for name in var.names: {
    foo = name
  }
]