Mcar49
Mcar49

Reputation: 327

Terraform - Ignore part of a variable's value if it equals a certain value

I am trying to create a multi-cloud solution for building out security rules for EC2/GCE instances. The idea is that I only want to use a single .tfvars file which works for both platforms.

Everything works, however, because of a discrepancy between AWS & GCP (AWS requires you to provide a port value of -1 and GCP requires that you don't provide a port when defining an ICMP rule), my solution doesn't entirely work. Here's a snippet of my .tfvars:

rules = [
 {
    protocol = "tcp"
    port = 22
    cidrs = ["10.0.0.0/8"]
  },
  {
    protocol = "icmp"
    port = -1
    cidrs = ["10.0.0.0/8"]
  }
]

These are passed into variables.tf:

variable "rules" {
  type = list(object({
    protocol = string
    port = number
    cidrs = list(string)
  }))
}

Which are then accessed using dynamic blocks. Here's the example for GCP:

resource "google_compute_firewall" "this" {
  name        = "rule"
  network     = "network"
  project     = "project"
  target_tags = "targets"

  dynamic "allow" {
    for_each = var.rules

    content{
      protocol = allow.value["protocol"]
      ports    = [allow.value["port"]]
    }
  }
}

So essentially, I either need to tell the GCP module to ignore allow.value["port"] when it equals -1, or I need to not define the port for ICMP in my .tfvars file, and tell AWS to add -1 as a port number when allow.value["protocol"] is equal to icmp.

Any suggestions on how to achieve either of these would be greatly appreciated!

Upvotes: 1

Views: 816

Answers (1)

ydaetskcoR
ydaetskcoR

Reputation: 56859

Terraform 0.12, as well as introducing dynamic blocks, introduced null which will omit sending the attribute to the provider.

This works nicely when you have something conditional and the provider isn't happy with say an empty string to mean that it's being omitted (a common trick pre 0.12).

So for you you could do this:

resource "google_compute_firewall" "this" {
  name        = "rule"
  network     = "network"
  project     = "project"
  target_tags = "targets"

  dynamic "allow" {
    for_each = var.rules

    content{
      protocol = allow.value["protocol"]
      ports    = allow.value["port"] == -1 ? null : [allow.value["port"]]
    }
  }
}

Now if you set port to -1 then it will omit the ports attribute from the allow block but otherwise it sets it to the value of the rules.port.

Upvotes: 3

Related Questions