regexazureterraformterraform-provider-azure

Get Azure keyvault id from two types of Terraform variable inputs


I have two types of variables in terrafrom.

First two are object() type

 variable "var1" {
  type = object({
   host_name                       = string
   key_vault_id                    = optional(string)
  })
 default = {
    host_name     = "api.example.com"
   key_vault_id  = "https://keyvault1.vault.azure.net/secrets/example-cert1"

  }
}

 variable "var2" {
   type = object({
    host_name                       = string
    key_vault_id                    = optional(string)
   })
   default = {
   host_name     = "portal.example.com"
   key_vault_id  = "https://keyvault2.vault.azure.net/secrets/example-cert2"
 }
}

and, second one is map(object())

 variable "var3" {
  type = map(object({
    value              = string
   secret             = bool
   secret_id          = optional(string)
   identity_client_id = optional(string)
  }))
  default = {
    "my-named-value-1" = {
     value              = ""
     secret             = true
     secret_id          = "https://keyvault3.vault.azure.net/secrets/secret1003"
   }
 "my-named-value-2" = {
     value              = ""
      secret             = true
      secret_id          = "https://keyvault4.vault.azure.net/secrets/secret1003"
   }
  }
 }

To extract the key vault id from this variable i'm using the below code

 locals {
   key_vault_names = distinct(
    compact(
      concat(
        [
          var.var1!= null ? regex("https://([a-zA-Z0-9-]{3,24})", var.var1.key_vault_id) : null,
          var.var2!= null ? regex("https://([a-zA-Z0-9-]{3,24})", var.var2.key_vault_id) : null
        ],
        [
          for value in values(var.var3) : regex("https://([^.]+).vault.azure.net", value.secret_id) if value.secret_id != ""
       ]
     )
   )
  )
}

 data "azurerm_key_vault" "key_vaults" {
  for_each = toset(local.key_vault_names)
  name     = each.key
  resource_group_name = var.resource_group_name
 }

locals {
  key_vault_ids = [
    for kv in data.azurerm_key_vault.key_vaults : kv.id
   ]
 }

But it is failing because of below code

Error: Invalid function argument
│ 
│
│   26:     compact(
│   27:       concat(
 │   28:         [
│   29:            var.var1!= null ? regex("https://([a-zA-Z0-9-]{3,24})", 
var.var1.key_vault_id) : null,
         var.var2!= null ? regex("https://([a-zA-Z0-9-]{3,24})", var.var2.key_vault_id) 
  : null
  │   32:         ],
  │   33:         # [
  │   34:         #   for value in values(var.var3) : 
 regex("https://([^.]+).vault.azure.net", value.secret_id) if value.secret_id != ""
 │   35:         # ]
 │   36:       )
 │   37:     )
 │     ├────────────────
 │     │ while calling compact(list)
 │     │ var.var2 is a object
 │     │ var.var2.key_vault_id is a string
 │     │ var.var1 is a object
 │     │ var.var1.key_vault_id is a string
 │     │ var.var3 is map of object with 2 elements

 │ 
 │ Invalid value for "list" parameter: element 0: string required.
 ╵
   Operation failed: failed running terraform plan (exit 1)

Solution

  • Fetching Azure keyvault id from two types of Terraform variable inputs

    As per the document the regex function returns a list but you're referring it to place where it requires string.

    Retry changing your locals as mentioned below so that you fetch the key vault ids as required.

    Configuration:

    variable "var1" {
      type = object({
        host_name    = string
        key_vault_id = optional(string)
      })
      default = {
        host_name    = "api.example.com"
        key_vault_id = "https://tesagsbvk.vault.azure.net/secrets/secret1"
      }
    }
    
    variable "var2" {
      type = object({
        host_name    = string
        key_vault_id = optional(string)
      })
      default = {
        host_name    = "portal.example.com"
        key_vault_id = "https://tesagsbvk2.vault.azure.net/secrets/secret2"
      }
    }
    
    variable "var3" {
      type = map(object({
        host_name    = string
        key_vault_id = optional(string)
      }))
      default = {
        "tesagsbvk5" = {
          host_name    = "app.example.com"
          key_vault_id = "https://tesagsbvk5.vault.azure.net/secrets/secret5"
        }
        "tesagsbvk6" = {
          host_name    = "service.example.com"
          key_vault_id = "https://tesagsbvk6.vault.azure.net/secrets/secret6"
        }
      }
    }
    
    locals {
      key_vault_names = compact(concat(
        [
          length(regexall("https://([a-zA-Z0-9-]+).vault.azure.net/secrets/.*", var.var1.key_vault_id)) > 0 ? regex("https://([a-zA-Z0-9-]+).vault.azure.net/secrets/.*", var.var1.key_vault_id)[0] : "",
          length(regexall("https://([a-zA-Z0-9-]+).vault.azure.net/secrets/.*", var.var2.key_vault_id)) > 0 ? regex("https://([a-zA-Z0-9-]+).vault.azure.net/secrets/.*", var.var2.key_vault_id)[0] : "",
        ],
        [for value in var.var3 : (
          length(regexall("https://([a-zA-Z0-9-]+).vault.azure.net/secrets/.*", value.key_vault_id)) > 0 ? regex("https://([a-zA-Z0-9-]+).vault.azure.net/secrets/.*", value.key_vault_id)[0] : ""
        )]
      ))
    }
    
    data "azurerm_key_vault" "key_vaults" {
      for_each = toset(local.key_vault_names)
      name     = each.key
      resource_group_name = "vinay-rg"  
    }
    
    output "key_vault_ids" {
      value = {
        for name, key_vault in data.azurerm_key_vault.key_vaults : name => key_vault.id
      }
    }
    

    Deployment:

    enter image description here

    Refer:

    https://developer.hashicorp.com/terraform/language/functions/regex

    https://registry.terraform.io/providers/hashicorp/assert/latest/docs/functions/regex

    https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/waf_regex_match_set.html