Validating elements of complex map() type variable

Hi there,

I have a variable block (in .tfvars) like this:

target_accounts = {
  Red = {
    account_id  = "111111111111"
    allowed_ips = "0.0.0.0/0"
  }
  Green = {
    account_id  = "222222222222"
    allowed_ips = "0.0.0.0/0"
  }
  Xxx = { ... }
}

and then it just declared using thevariable block, like:

variable "target_accounts" {
  type        = map
  description = "list of AWS member a/c" 
}

Is it any way possible to use validation {..} block abd something like (length(var.iam_account_id) == 12) as a condition to make sure that all of the account_ids are correctly formatted with correct number of digits? I don’t want to change the code in the module, every time new member (e.g. Blue { ... }) is added to the map .

Any pointer(s)?

-S

Starting with Terraform 0.14, you can use the alltrue and anytrue functions to help with this. Here’s an example:

variable "target_accounts" {
  type = map(object({
    account_id: string,
    allowed_ips: string,
  }))

  default = {
    Red = {
      account_id  = "111111111111"
      allowed_ips = "0.0.0.0/0"
    }
    Green = {
      account_id  = "222222222222"
      allowed_ips = "0.0.0.0/0"
    }
    Blue = {
      account_id  = "33333333333"
      allowed_ips = "0.0.0.0/0"
    }
  }

  validation {
    condition = alltrue([
      for account in values(var.target_accounts):
        length(account.account_id) == 12
      ])
    error_message = "All account IDs must have 12 characters."
  }
}

thanks @alisdair for quick reply. :+1:
We still have a couple of months to go to upgrade to v14; anything can be done in v13? No workaround at all?

(future-proofing the near-future though with that :+1:)

-S

Yes, for 0.13 you can use !contains(…, false) instead of alltrue, and contains(…, true) for anytrue. The validation below is equivalent, just a bit less clear to read:

  validation {
    condition = !contains([
      for account in values(var.target_accounts):
        length(account.account_id) == 12
      ], false)
    error_message = "All account IDs must have 12 characters."
  }
1 Like

thanks a lot!!
What exactly was looking for. Probably couldn’t figure out without this help easily.

-S

Sorry, I think I have a follow up Q: How do I validate a list element (as opposed to a string type) as the account_id? Say this example:

variable "trusted_accounts" {
  type = map(object({
    account_ids: list(string),
    chk_ipaddr: bool,
  }))

  default = {
    Role1 = {
    account_ids = [
      "111111111111",
      "222222222222",
    ]
    chk_ipaddr = false
  }
  Role2 = {
    account_ids = [
      "111111111111",
      "333333333333",
    ]
    chk_ipaddr = true
  }
}

I tried with this:

validation {
    condition = !contains([
      for role in values(var.trusted_accounts):
        [for acc in role.account_ids : length(acc) == 12]
      ], false)
    error_message = "Incorrect account-id for one or more trusted a/c."
}

but always coming as true. If I change it to:

for role in values(var.trusted_accounts):
    [for acc in role.account_ids : length(acc)] == 12
]

always returning false. What else am I missing here?

-S

Have you upgraded to terraform 0.14 and looked into those validation block docs?

Or is the question rather how to apply the validation to map blocks?

Input Variables - Configuration Language - Terraform by HashiCorp

We are still couple of months away to start upgrading to v14, so still on v13. This question is how to the validation to map but when one of the map elements is a list and need to validate the list element(s). It’s working with no issue on string type, as per the @alisdair 's suggestion.

for the completeness (and if anyone else is on the same boat as me), I rewrote (used the RegEx instead) the condition like this:

condition = !contains([
    for acc in flatten([for role in values(var.trusted_entities) :
                            [for id in role.acc_ids : id]]) :
        can(regex("^[\\d]{12}$", acc))
], false)

and that should validate the elements inacc_ids in this map():

type = map(object({
    acc_ids : list(string),
    chk_ipaddr : bool,
}))

I’d be interested to know if there is a better way to deal with cases like this.

-S