Terraform for_each 循环。索引无效

Terraform for_each loop. Invalid index

我在 terraform 中遇到 for_each 循环问题。

我有一个 managed_keys 的 azure 资源如下:

resource "azurerm_storage_account_customer_managed_key" "storage-managed-key" {
  for_each = toset(var.key-name)
  key_name = "Key-Client-${each.value}"
  key_vault_id = azurerm_key_vault.tenantsnbshared.id
  key_version = azurerm_key_vault_key.client-key[each.value].version
  storage_account_id = azurerm_storage_account.storage-foreach[each.value].identity.0.principal_id
  depends_on = [azurerm_key_vault_access_policy.storage]
}

我有一个名为 key-name 的变量和一个存储帐户 storage-foreach,它们都有一个 list(string) 和一些值。

我的目标是能够遍历这 2 个变量并使用相应的密钥加密存储帐户。

但是如果我 运行 我的代码,我会得到这个错误:

Error: Invalid index

  on main.tf line 173, in resource "azurerm_storage_account_customer_managed_key" "storage-managed-key":
 173:   storage_account_id = azurerm_storage_account.storage-foreach[each.value].identity.0.principal_id
    |----------------
    | azurerm_storage_account.storage-foreach is object with 4 attributes
    | each.value is "key-name"

The given key does not identify an element in this collection value.

编辑:

resource "azurerm_storage_account" "storage-foreach" {
  for_each                 = toset(var.storage-foreach)
  access_tier              = "Hot"
  account_kind             = "StorageV2"
  account_replication_type = "LRS"
  account_tier             = "Standard"
  location                 = var.location
  name                     = each.value
  resource_group_name      = azurerm_resource_group.tenant-testing-hamza.name

  identity {
    type = "SystemAssigned"
  }

  lifecycle {
    prevent_destroy = false
  }
}


Key vault access policies:
resource "azurerm_key_vault_access_policy" "storage" {
  for_each           = var.storage-foreach
  key_vault_id       = azurerm_key_vault.tenantsnbshared.id
  tenant_id          = "<tenant-id>"
  object_id          = azurerm_storage_account.storage-foreach[each.value].identity.0.principal_id
  key_permissions    = ["get", "Create", "List", "Restore", "Recover", "Unwrapkey", "Wrapkey", "Purge", "Encrypt", "Decrypt", "Sign", "Verify", "Delete"]
  secret_permissions = ["get", "set", "list", "delete", "recover"]
  depends_on = [azurerm_key_vault.tenantsnbshared]
}

variable "storage-foreach" {
  type    = map(string)
  default = { "<name1>" = "storage1", "<name2>" = "storage2", "<name3>" = "storage3", "<name4>" = "storage4"}
}

variable "key-name" {
  type    = map(string)
  default = {"<name1>" = "key1", "<name2>" = "<key2>", "name3" = "<key3>", "<name4>" = "key4"}
}

我的键名变量中的每个元素都会重复此错误。

我尝试了一些方法,但使用 count 而不是 for_each,它工作得很好,但我遇到的问题是,如果我想删除第一个存储帐户和第一个键,它会自动销毁后面的所有元素,然后重新创建它们,这不是我想要做的。

有没有人可以帮助我理解这个错误以及如何解决它?

我假设包含密钥和存储帐户的列表长度相同,并且您要使用密钥编号 加密存储帐户编号 i。您可以使用“旧式”、基于索引的循环或将两个列表压缩到一个元组列表中,然后遍历压缩列表。

解决方案 1:使用基于索引的迭代

此解决方案不使用 for_each,而是使用元参数 count。这种在 Terraform 中迭代资源的方式早于较新的 for_each 样式。

resource "azurerm_storage_account_customer_managed_key" "storage-managed-key" {
  count = length(var.key-name)
  key_name = azurerm_key_vault_key.client-key[var.key-name[count.index]].name
  key_vault_id = azurerm_key_vault_key.client-key[var.key-name[count.index]].key_vault_id
  key_version = azurerm_key_vault_key.client-key[var.key-name[count.index]].version
  storage_account_id = azurerm_storage_account.storage-foreach[var.storage-foreach[count.index]].identity.0.principal_id
  depends_on = [azurerm_key_vault_access_policy.storage]
}

我冒昧地通过引用您的密钥资源的属性来替换显式密钥名称和密钥保管库 ID。

方案二:使用组合结构

这里的想法是创建一个可以迭代的结构,其中的元素结合了键名和存储帐户名。有多种方法可以做到这一点。最简单的方法可能是“滥用”映射并将其视为元组列表,然后您可以简单地使用 zipmap.

resource "azurerm_storage_account_customer_managed_key" "storage-managed-key" {
  for_each = zipmap(var.storage-foreach, var.key-name)
  key_name = azurerm_key_vault_key.client-key[each.value].name
  key_vault_id = azurerm_key_vault_key.client-key[each.value].key_vault_id
  key_version = azurerm_key_vault_key.client-key[each.value].version
  storage_account_id = azurerm_storage_account.storage-foreach[each.key].identity.0.principal_id
  depends_on = [azurerm_key_vault_access_policy.storage]
}

请注意,我选择 var.storage-foreach 作为对象的键,这可能令人困惑。选择密钥作为映射密钥将无法使用相同的密钥来加密多个存储帐户。由于 storage-foreach 已经用于索引 Terraform 资源,我也已经知道这些遵守 Terraform 命名限制。

有什么区别?

在解决方案 1 中,您的 azurerm_storage_account_customer_managed_key 资源名称是基于整数的。重新排序列表中的元素可能会导致 Terraform 销毁并重新创建资源。解决方案 2 并非如此,这就是为什么我通常更喜欢解决方案 2。但是,在这种情况下,解决方案 1 可能具有更直接的优势。

一个建议...

如果可能,我建议重新评估您定义变量的方式。首先要求包含密钥名称和存储帐户的对象列表可能更有意义;那么您基本上可以使用解决方案 2 而无需调用 zipmap。像这样在两个变量之间建立隐式依赖关系几乎不是一个好主意 - 这些列表必须具有相同的长度,并且隐式地,列表的内容通过具有相同的索引来连接。