使用 Terraform 在 Azure 中创建多个 VM 并为这些 VM 分配角色。 (坚持 for_each 循环)

Creating multiple VMs & assigning role to those VMs in Azure using Terraform. (Stuck with for_each loop)

我正在尝试在 Azure 中创建多个虚拟机。我正在使用 CSV 文件传递​​虚拟机名称值,如下所示。

此外,我计划使用电子邮件列在 vm 上分配这些用户 reader 角色,基本上我计划为我的 csv 中的每个名称创建 1 个 vm 并分配那个人 reader 角色在相应的虚拟机上。

我能够基于我的 CSV 文件成功创建 Vms,但是在分配角色时我无法理解如何去做。

下面是我创建虚拟机的代码:

    terraform {
    required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "2.77.0"
      }
    azuread = {
      source  = "hashicorp/azuread"
      version = "~> 2.0.0"
      }}}

provider "azuread" {
  tenant_id = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

data "azurerm_client_config" "example" {
}

locals {
  group_names = csvdecode(file("./test.csv"))
  users     = { for r in local.group_names : r.email => r }
  
}


data "azurerm_subnet" "exisiting_subnet" {
  name                 = "default"
  virtual_network_name = "rg-sarmad-calico-001-vnet"
  resource_group_name  = "rg-sarmad-calico-001"
}

resource "azurerm_network_interface" "new_terraform_vm_nic" {
  for_each = {for group_names in local.group_names : group_names.names => group_names}
  name = "nic-${each.value.names}-001"
 
  location            = "westeurope"
  resource_group_name = data.azurerm_subnet.exisiting_subnet.resource_group_name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = data.azurerm_subnet.exisiting_subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_windows_virtual_machine" "new_terraform_vm" {
  for_each = {for group_names in local.group_names : group_names.names => group_names}
  name =      "vm-${each.value.names}-001"
  resource_group_name = data.azurerm_subnet.exisiting_subnet.resource_group_name
  location            = "westeurope"
  size                = "Standard_F2"
  admin_username      = "adminuser"
  admin_password      = "P@$$w0rd1234!"
  network_interface_ids = [azurerm_network_interface.new_terraform_vm_nic[each.key].id]
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
    version   = "latest"
  }
}

使用 for_each 循环我可以创建 VMS,现在我想使用他们的电子邮件在这些 VMS 上分配我的 csv 角色中的用户,这些用户已经存在于 AD 中,所以我写了下面的代码:



data "azuread_user" "user" {
    for_each = {for group_names in local.group_names : group_names.email => group_names}
    user_principal_name = each.value.email
}


resource "azurerm_role_assignment" "new_terraform_vm_rbac" {
# for_each = {for group_names in local.group_names : group_names.names => group_names}
  for_each               = data.azuread_user.user

  scope                =  "/subscriptions/${data.azurerm_client_config.example.subscription_id}/resourceGroups/${data.azurerm_subnet.exisiting_subnet.resource_group_name}/providers/Microsoft.Compute/virtualMachines/${"vm-${each.value.names}-001"}" 
  role_definition_name = "Reader"
  principal_id         = data.azuread_user.user[each.key].object_id
}


我在“azurerm_role_assignment”中的每个循环都有两个,第一个被注释但使用该循环我可以从 CSV 中获取名称,这在下面定义角色分配的范围时需要&我也需要来自 azuread_user 的数据,这些数据将用于在“azurerm_role_assignment”中定义 principle_id。

我被卡住了,不明白我该如何实现,我正在寻找任何可能的建议。

您必须使用 principal_id= data.azuread_user.user[each.value.email].object_id 而不是 principal_id = data.azuread_user.user[each.key].object_id

所以你的全部代码如下:

    terraform {
    required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "2.77.0"
      }
    azuread = {
      source  = "hashicorp/azuread"
      version = "~> 2.0.0"
    }
  }
}

provider "azuread" {
}

provider "azurerm" {
    features{}
}

data "azurerm_client_config" "example" {
}

locals {
  group_names = csvdecode(file("C:/test.csv"))
  users     = { for r in local.group_names : r.email => r }
}

data "azurerm_subnet" "exisiting_subnet" {
  name                 = "default"
  virtual_network_name = "ansuman-vnet"
  resource_group_name  = "resourcegroup"
}

resource "azurerm_network_interface" "new_terraform_vm_nic" {
  for_each = {for group_names in local.group_names : group_names.names => group_names}
  name = "nic-${each.value.names}-001"
 
  location            = "West US 2"
  resource_group_name = data.azurerm_subnet.exisiting_subnet.resource_group_name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = data.azurerm_subnet.exisiting_subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_windows_virtual_machine" "new_terraform_vm" {
  for_each = {for group_names in local.group_names : group_names.names => group_names}
  name =      "vm-${each.value.names}-001"
  resource_group_name = data.azurerm_subnet.exisiting_subnet.resource_group_name
  location            = "West US 2"
  size                = "Standard_F2"
  admin_username      = "adminuser"
  admin_password      = "P@$$w0rd1234!"
  network_interface_ids = [azurerm_network_interface.new_terraform_vm_nic[each.key].id]
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }
  

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
    version   = "latest"
  }
}

data "azuread_user" "user" {
    for_each = {for group_names in local.group_names : group_names.email => group_names}
    user_principal_name = each.value.email
}

resource "azurerm_role_assignment" "new_terraform_vm_rbac" {
 for_each = {for group_names in local.group_names : group_names.names => group_names}
  scope                =  "/subscriptions/${data.azurerm_client_config.example.subscription_id}/resourceGroups/${data.azurerm_subnet.exisiting_subnet.resource_group_name}/providers/Microsoft.Compute/virtualMachines/${"vm-${each.value.names}-001"}" 
  role_definition_name = "Reader"
  principal_id         = data.azuread_user.user[each.value.email].object_id

  depends_on = [
    azurerm_windows_virtual_machine.new_terraform_vm
  ]
}

输出:

注:

您必须在角色分配块中使用 depends_on =[azurerm_windows_virtual_machine.new_terraform_vm],因为如果未提供依赖项,将首先创建角色分配,并且在创建资源后您将收到错误消息,指出没有角色分配设置是因为找不到如下所示的 VM。此外,对于角色分配,您需要拥有订阅的所有者访问权限,或者至少是您尝试分配角色的资源组。