如何通过Terraform跨Azure订阅复用默认NSG至多VM/NIC
跨订阅NSG关联的Terraform实现方案
要实现将一个Azure订阅中的NSG附加到其他订阅的VM或NIC上,核心是配置多订阅的Terraform Azure Provider,并确保权限覆盖两个订阅,以下是具体步骤和代码示例:
1. 配置多订阅Azure Provider
需要初始化两个Provider实例,分别对应源订阅(创建/托管NSG的订阅)和目标订阅(VM/NIC所在的订阅),通过alias区分:
# 源订阅Provider(用于创建/读取NSG) provider "azurerm" { alias = "source_sub" subscription_id = "源订阅ID" tenant_id = "租户ID" # 认证方式按需选择(服务主体、Azure CLI等) client_id = "服务主体ID" client_secret = "服务主体密钥" } # 目标订阅Provider(用于管理VM/NIC) provider "azurerm" { alias = "target_sub" subscription_id = "目标订阅ID" tenant_id = "租户ID" client_id = "服务主体ID" client_secret = "服务主体密钥" }
注意:使用的服务主体必须同时拥有源订阅的NSG读取权限和目标订阅的NIC修改/创建权限,否则会触发权限不足错误。
2. 在源订阅中创建或引用NSG
场景1:创建新的跨订阅NSG
如果NSG尚未存在,在源订阅中定义NSG资源:
resource "azurerm_network_security_group" "cross_sub_nsg" { provider = azurerm.source_sub name = "cross-sub-default-nsg" location = "eastus" resource_group_name = "源订阅资源组名" # 按需添加安全规则示例 security_rule { name = "allow-rdp" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "3389" source_address_prefix = "*" destination_address_prefix = "*" } }
场景2:引用已存在的NSG
如果NSG已在源订阅中创建,通过数据源直接引用:
data "azurerm_network_security_group" "existing_nsg" { provider = azurerm.source_sub name = "已存在的NSG名称" resource_group_name = "源订阅资源组名" }
3. 在目标订阅中关联NSG到NIC/VM
方式1:关联到现有NIC
通过数据源获取目标订阅中的NIC,更新其network_security_group_id字段关联跨订阅NSG:
# 获取目标订阅中的现有NIC data "azurerm_network_interface" "target_nic" { provider = azurerm.target_sub name = "目标NIC名称" resource_group_name = "目标订阅资源组名" } # 更新NIC关联跨订阅NSG resource "azurerm_network_interface" "updated_nic" { provider = azurerm.target_sub name = data.azurerm_network_interface.target_nic.name location = data.azurerm_network_interface.target_nic.location resource_group_name = data.azurerm_network_interface.target_nic.resource_group_name # 保留原NIC的IP配置 ip_configuration { name = data.azurerm_network_interface.target_nic.ip_configuration[0].name subnet_id = data.azurerm_network_interface.target_nic.ip_configuration[0].subnet_id private_ip_address_allocation = data.azurerm_network_interface.target_nic.ip_configuration[0].private_ip_address_allocation public_ip_address_id = data.azurerm_network_interface.target_nic.ip_configuration[0].public_ip_address_id } # 关联源订阅的NSG(创建新NSG用azurerm_network_security_group.cross_sub_nsg.id,引用现有则用data.azurerm_network_security_group.existing_nsg.id) network_security_group_id = azurerm_network_security_group.cross_sub_nsg.id }
方式2:创建新VM时关联NSG
在目标订阅中创建VM时,直接在NIC配置中指定跨订阅NSG的ID:
# 获取目标订阅中的子网 data "azurerm_subnet" "target_subnet" { provider = azurerm.target_sub name = "目标子网名称" virtual_network_name = "目标VNet名称" resource_group_name = "目标订阅资源组名" } # 创建关联跨订阅NSG的新NIC resource "azurerm_network_interface" "new_vm_nic" { provider = azurerm.target_sub name = "new-vm-nic" location = "eastus" resource_group_name = "目标订阅资源组名" ip_configuration { name = "internal" subnet_id = data.azurerm_subnet.target_subnet.id private_ip_address_allocation = "Dynamic" } network_security_group_id = azurerm_network_security_group.cross_sub_nsg.id } # 创建VM并使用上述NIC resource "azurerm_linux_virtual_machine" "new_cross_sub_vm" { provider = azurerm.target_sub name = "cross-sub-demo-vm" resource_group_name = "目标订阅资源组名" location = "eastus" size = "Standard_D2s_v3" admin_username = "adminuser" network_interface_ids = [azurerm_network_interface.new_vm_nic.id] admin_ssh_key { username = "adminuser" public_key = file("~/.ssh/id_rsa.pub") } os_disk { caching = "ReadWrite" storage_account_type = "Premium_LRS" } source_image_reference { publisher = "Canonical" offer = "0001-com-ubuntu-server-jammy" sku = "22_04-lts" version = "latest" } }
核心注意事项
- 权限要求:服务主体在源订阅需拥有
Network Security Groups Reader角色,在目标订阅需拥有Network Contributor角色(或更细粒度的NIC修改权限)。 - 区域一致性:NSG与目标NIC必须位于同一Azure区域,否则无法关联。
- 状态管理:Terraform状态会记录跨订阅资源关联,后续变更需确保Provider配置稳定。
内容的提问来源于stack exchange,提问作者huju vert
相关产品推荐
相关产品推荐

