使用 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。此外,对于角色分配,您需要拥有订阅的所有者访问权限,或者至少是您尝试分配角色的资源组。
我正在尝试在 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。此外,对于角色分配,您需要拥有订阅的所有者访问权限,或者至少是您尝试分配角色的资源组。