How to use multiple keyvaults and use loops or for_each?

I have 5 keyvaults with 5 secrets the trouble is dont want my terraform file to have 10 data blocks like this:

    data "azurerm_key_vault" "kv1" {
      name                = "mykeyvault"
      resource_group_name = "myrg"
    }

    data "azurerm_key_vault_secret" "kv1" {
      name         = var.secret_name
      key_vault_id = var..key_vault_id
    }
    data "azurerm_key_vault" "kv2" {
      name                = "mykeyvault"
      resource_group_name = "myrg"
    }

    data "azurerm_key_vault_secret" "kv2" {
      name         = var.secret_name
      key_vault_id = var..key_vault_id
    }
    data "azurerm_key_vault" "kv3" {
      name                = "mykeyvault"
      resource_group_name = "myrg"
    }

    data "azurerm_key_vault_secret" "kv3" {
      name         = var.secret_name
      key_vault_id = var..key_vault_id
    }
    data "azurerm_key_vault" "kv4" {
      name                = "mykeyvault"
      resource_group_name = "myrg"
    }

    data "azurerm_key_vault_secret" "kv4" {
      name         = var.secret_name
      key_vault_id = var..key_vault_id
    }
    data "azurerm_key_vault" "kv5" {
      name                = "mykeyvault"
      resource_group_name = "myrg"
    }

    data "azurerm_key_vault_secret" "kv5" {
      name         = var.secret_name
      key_vault_id = var..key_vault_id
    }
    .....

is there any other way i can use in one block to assign 5 keyvaults data blocks and 5 secrets data blocks?

for example: (most likely wrong)

data "azurerm_key_vault" "kv1" {

  for_each = toset(var.keyvaults)

  name                = each.key

  resource_group_name = var.rg

}

data "azurerm_key_vault_secret" "keys" {

  name         = var.keyvaults[each.value]

  key_vault_id = var.keyvaultid[each.value] 

}

Thanks

Hi @r.a.y,

From your example I’m understanding that you have a set of secret values you want to retrieve from some key vaults for use elsewhere in your configuration, and you’re trying to define them more concisely. It looks like (based on how you’ve set up your variables) you might be writing a data-only module to encapsulate fetching these so they are easier to use by another module.

Given that, I might design such a module like this:

variable "resource_group_name" {
  type = string
}

variable "secrets" {
  type = map(object({
    key_vault_name = string
    secret_name    = string
  }))
}

data "azurerm_key_vault" "all" {
  for_each = var.secrets

  name                = each.value.key_vault_name
  resource_group_name = var.resource_group_name
}

data "azurerm_key_vault_secret" "all" {
  for_each = var.secrets

  key_vault_id = data.azurerm_key_vault.all[each.key].id
  name         = each.value.secret_name
}

output "values" {
  value = {
    for k, s in data.azurerm_key_vault_secret.all : k => s.value
  }
  sensitive = true
}

The idea of this module is that a caller can provide a description of the secrets they need using a map of objects inside the calling module block, perhaps like this:

module "secrets" {
  source = "../modules/key-vault-secrets"

  resource_group_name = "ExampleThing"
  secrets = {
    example1 = {
      key_vault_name = "ExampleVault1"
      secret_name    = "ExampleSecretA"
    }
    example2 = {
      key_vault_name = "ExampleVault1"
      secret_name    = "ExampleSecretB"
    }
    example3 = {
      key_vault_name = "ExampleVault2"
      secret_name    = "ExampleSecretA"
    }
  }
}

For each element of var.secrets, it’ll look up the given vault name to find the vault ID, and then look up the given secret name in the vault it found.

It then exports just a map from the keys in var.secrets to the secret values retrieved in the values output value. Elsewhere in the calling module then, the caller could access those secrets using expressions like module.secrets.values.example1, module.secrets.values.example2, etc.

I hope this is close enough to your intended goal to be useful!

Hi @apparentlymart

Your absolutely right, I am trying to call the keyvault from data sources so that I can pass the secret keys to other modules.

The 5 keyvaults already exists and created I am just trying to get the secret values from them for each region so I can pass the secret keys to servers etc in different modules e.g. US-dns-module then pass the US secret key like secretkey=data.azurerm_key_vault_secret.USkeyvault.value and using a keyvaukt data source block.

Your design module is what I need except the 5 keyvaults I have is in 5 different resource groups and each resource group is in different regions such as US, North Europe, UK, East Asia etc.

So using your design is there a way to call all the secrets from 5 keyvaults which all the keyvaults sit in different resource group on different regions?

And then I can pass the secret value like this : for each region module for example if its a US module which needs a vm password key then it be like: secretkey=data.azurerm_key_vault_secret.USkeyvault.value

Also my devops pipeline creates the resources based on the “region” pipeline variable. So if the pipeline region is “eastasia” is there anyway for me to pass the secretkey using data source and my region pipeline variable like this secretkey=data.azurerm_key_vault_secret.(var.region).keyvault.value and if the my pipeline variable is changed to “North Europe” the secretkey will be fetched from the keyvault in northeurope resource group.

Thank you for your help.

How do we convert output code to variable assignment e.g.

output "values" {
  value = {
    for k, s in data.azurerm_key_vault_secret.all : k => s.value
  }
  sensitive = true
}

to variable assignment:

module “mysql” {

users = {
for k, s in data.azurerm_key_vault_secret.all : k => s.value
}