Have optional sub-variables in required Terraform variable

I have created a module corresponding to the Azure Firewall Network Rule Collection. The module looks like this:

resource "azurerm_firewall_network_rule_collection" "fwnrc" {
  name                = "fwnrc-${var.name}"
  resource_group_name = var.resource_group_name

  azure_firewall_name = var.azure_firewall_name
  priority            = var.priority
  action              = var.action

  dynamic "rule" {
    for_each = var.rule != null ? [true] : []
    content {
      name                  = var.rule.name
      description           = var.rule.description
      source_addresses      = var.rule.source_addresses
      source_ip_groups      = var.rule.source_ip_groups
      destination_addresses = var.rule.destination_addresses
      destination_ip_groups = var.rule.destination_ip_groups
      destination_fqdns     = var.rule.destination_fqdns
      destination_ports     = var.rule.destination_ports
      protocols             = var.rule.protocols
    }
  }
}

The section of interest right now is the dynamic "rule", which has a corresponding variable defined like this:

variable "rule" {
  type = object({
    name                  = string
    description           = string
    source_addresses      = list(string)
    source_ip_groups      = list(string)
    destination_addresses = list(string)
    destination_ip_groups = list(string)
    destination_fqdns     = list(string)
    destination_ports     = list(string)
    protocols             = list(string)
  })
}

I know that it is possible to make the rule variable "Optional" by setting its default value to null. I want to go one step deeper and make the sub-variables* optional/required. For instance, in the resource documentation it is written that one must specify either *_addresses or *_ip_groups. The docs also says destination_fqdns is optional.

* Is there an actual name for these?

Since the rule variable is required by my module I get an error if I do not give explicit values to all sub-variables. My solution for now is to do the following:

module "firewall_network_rule_collection" {
  source = "/path/to/module"

  name                = "fwrc"
  azure_firewall_name = "afw"
  resource_group_name = "rg"
  priority            = 110
  action              = "Allow"

  rule = {
    description = "rule"
    name        = "rule"

    source_addresses = ["*"]
    source_ip_groups = null

    destination_ports = ["*"]
    destination_addresses = [
      "AzureContainerRegistry",
      "MicrosoftContainerRegistry",
      "AzureActiveDirectory"
    ]
    destination_fqdns     = null
    destination_ip_groups = null

    protocols = ["Any"]

  }

}

Note the null values. Can I get rid of these somehow?

--

I am using the following provider settings:

terraform {
  required_version = ">=1.0.11"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">=2.90.0"
    }
  }
}

Solution 1:

The experimental "optional" object type is currently available if one opts in.

Add the following to your module:

terraform {
  experiments = [module_variable_optional_attrs]
}

This allows the following:

variable "rule" {
  type = object({
    name                  = string
    description           = optional(string)
    source_addresses      = optional(list(string))
    source_ip_groups      = optional(list(string))
    destination_addresses = optional(list(string))
    destination_ip_groups = optional(list(string))
    destination_fqdns     = optional(list(string))
    destination_ports     = optional(list(string))
    protocols             = optional(list(string))
  })
}

Hopefully this feature makes it to a fully supported part of the next release.