已配置NSG仍触发Azure策略限制,Bicep子网部署失败求助
用户采用多层Bicep文件架构,通过PowerShell脚本调用az deployment mg what-if执行管理组级部署,已在parSubnets参数中配置了关联指定NSG的子网,但部署时仍触发名为**"子网必须关联网络安全组"**的Azure策略限制,提示资源vnet-02-prod被策略阻止。
相关代码与信息
PowerShell脚本片段
$TEMPLATEFILE="./infra-as-code/bicep/orchestration/hubPeeredSpoke/hubPeeredSpoke.bicep" Write-Host $paramsJson $updatedParamsJson = $updatedParamsJson.Replace('"', '\"') if ($action -eq "whatif") { az deployment mg what-if --name $NAME --location $LOCATION --management-group-id $MGID --template-file $TEMPLATEFILE --parameters "$paramsJson" --debug }
参数JSON输出
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "parAllowSpokeForwardedTraffic": { "value": false }, "parSpokeNetworkName": { "value": "vnet-02-prod" }, "parSubnets": { "value": [ { "name": "sub-001-prod", "privateEndpointNetworkPolicies": "Disabled", "privateLinkServiceNetworkPolicies": "Enabled", "addressPrefix": "100.100.100.90/24", "networkSecurityGroup": { "id": "/subscriptions/xxxxxx/resourceGroups/rg-prod-001/providers/Microsoft.Network/networkSecurityGroups/nsg-001" }, "delegations": [ { "name": "private", "serviceName": "Microsoft.Databricks/workspaces" } ] } ] } } }
hubPeeredSpoke.bicep片段
param parSubnets array = [] module modSpokeNetworking '../../modules/spokeNetworking/spokeNetworking.bicep' = { scope: resourceGroup(parPeeredVnetSubscriptionId, parResourceGroupNameForSpokeNetworking) name: varModuleDeploymentNames.modSpokeNetworking dependsOn: [ modResourceGroup ] params: { parSpokeNetworkName: parSpokeNetworkName parSpokeNetworkAddressPrefix: parSpokeNetworkAddressPrefix parDdosProtectionPlanId: parDdosProtectionPlanId parDnsServerIps: parDnsServerIps parNextHopIpAddress: varNextHopIPAddress parSpokeToHubRouteTableName: parSpokeToHubRouteTableName parDisableBgpRoutePropagation: parDisableBgpRoutePropagation parTags: parTags parTelemetryOptOut: parTelemetryOptOut parLocation: parLocation parSubnets: parSubnets } }
spokeNetworking.bicep片段
param parSubnets array = [] resource resSpokeVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-02-01' = { name: parSpokeNetworkName location: parLocation tags: parTags properties: { addressSpace: { addressPrefixes: [ parSpokeNetworkAddressPrefix ] } enableDdosProtection: (!empty(parDdosProtectionPlanId)? true : false) ddosProtectionPlan: (!empty(parDdosProtectionPlanId)? true : false)? { id: parDdosProtectionPlanId } : null dhcpOptions: (!empty(parDnsServerIps)? true : false)? { dnsServers: parDnsServerIps } : null subnets: parSubnets } }
报错信息
RequestDisallowedByPolicy - 资源 'vnet-02-prod' 被策略阻止。策略标识符: '[{"policyAssignment":{"name":"子网必须关联网络安全组","id":"/providers/Microsoft.Management/managementGroups/landingzones/alz/providers/Microsoft.Authorization/policyAssignments/Deny-Subnet-Without-Nsg"},"policyDefinition":{"name":"子网必须关联网络安全组","id":"/providers/Microsoft.Management/managementGroups/landingzones/alz/providers/Microsoft.Authorization/policyDefinitions/Deny-Subnet-Without-Nsg"}}]'。
排查与解决方法
1. 拆分子网资源定义,明确部署顺序
当前Bicep将子网作为VNet的嵌套属性传入,策略评估可能在VNet创建时无法正确识别子网的NSG关联。将子网拆分为独立资源,显式绑定NSG:
修改spokeNetworking.bicep:
param parSubnets array = [] resource resSpokeVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-02-01' = { name: parSpokeNetworkName location: parLocation tags: parTags properties: { addressSpace: { addressPrefixes: [ parSpokeNetworkAddressPrefix ] } enableDdosProtection: (!empty(parDdosProtectionPlanId)? true : false) ddosProtectionPlan: (!empty(parDdosProtectionPlanId)? true : false)? { id: parDdosProtectionPlanId } : null dhcpOptions: (!empty(parDnsServerIps)? true : false)? { dnsServers: parDnsServerIps } : null } } // 单独定义子网资源,显式关联NSG resource resSubnets 'Microsoft.Network/virtualNetworks/subnets@2023-02-01' = [for subnet in parSubnets: { parent: resSpokeVirtualNetwork name: subnet.name properties: { addressPrefix: subnet.addressPrefix privateEndpointNetworkPolicies: subnet.privateEndpointNetworkPolicies privateLinkServiceNetworkPolicies: subnet.privateLinkServiceNetworkPolicies networkSecurityGroup: subnet.networkSecurityGroup delegations: subnet.delegations } }]
2. 验证NSG ID有效性与部署权限
- 执行以下命令确认NSG存在:
az network nsg show --ids "/subscriptions/xxxxxx/resourceGroups/rg-prod-001/providers/Microsoft.Network/networkSecurityGroups/nsg-001" - 检查部署所用身份(用户/服务主体)是否拥有该NSG的
Microsoft.Network/networkSecurityGroups/read权限,避免策略评估时无法解析NSG资源。
3. 优化参数类型约束,确保属性传递正确
在spokeNetworking.bicep中为parSubnets参数添加明确的类型约束,避免参数传递过程中属性丢失或格式错误:
param parSubnets array = [ { name: string addressPrefix: string privateEndpointNetworkPolicies: string privateLinkServiceNetworkPolicies: string networkSecurityGroup: { id: string } delegations: array } ]
4. 检查策略定义的具体规则
查看策略的详细规则,确认是否存在额外约束(如NSG与子网同资源组、NSG包含特定规则等):
az policy definition show --id "/providers/Microsoft.Management/managementGroups/landingzones/alz/providers/Microsoft.Authorization/policyDefinitions/Deny-Subnet-Without-Nsg"
内容的提问来源于stack exchange,提问作者Bob

