🐛 Problem
Upgrading FinOps hub with private networking enabled (enablePublicAccess: false) is destructive to the existing network configuration. The template does not account for an already-deployed private hub and attempts to re-create or reconcile VNet and subnet resources as if performing a fresh deployment. This breaks existing private networking in two ways:
Issue 1 — Subnet deletion: The template defines the 3 hub subnets inline inside the Microsoft.Network/virtualNetworks resource (subnets: [...]). ARM treats this inline list as the complete desired state and attempts to delete any subnet not in the list. This breaks user-added subnets (e.g. a Power BI Gateway subnet with a Microsoft.PowerPlatform/vnetaccesslinks service association link), causing the deployment to fail with InUseSubnetCannotBeDeleted.
Issue 2 — No upgrade-safe path for existing private networking: Even when the subnet error is avoided, the upgrade redeploys all private networking infrastructure (NSG, VNet, DNS zones, private endpoints) without any mechanism to detect or preserve existing configurations, putting connectivity for dependent services (Power BI Gateway, ADX client connections, peered spoke VNets) at risk during deployment.
👣 Repro steps
- Deploy FinOps hub 0.12 (or any prior version) with enablePublicAccess: false
- After initial deployment, add a custom subnet to the hub VNet — e.g. a Power BI Gateway subnet (pbi-network-data-gw-subnet) delegated to Microsoft.PowerPlatform/vnetaccesslinks for connecting Power BI reports to the ADX cluster
- Upgrade to FinOps hub v14 by redeploying the template against the same resource group with identical hubName, enablePublicAccess: false, and virtualNetworkAddressPrefix parameters
- Observe deployment failure at Microsoft.FinOpsHubs.Core_Infrastructure:
{
"code": "InUseSubnetCannotBeDeleted",
"message": "Subnet pbi-network-data-gw-subnet is in use by ...subnets/pbi-network-data-gw-subnet/serviceAssociationLinks/PowerPlatformSAL and cannot be deleted."
}
- Even if the custom subnet is temporarily removed, re-running the upgrade redeploys the NSG, VNet, DNS zones, and private endpoints — disrupting active private endpoint connections during the deployment window.
🤔 Expected
Hub upgrades should be fully non-destructive to existing private networking:
Subnet preservation: The template should only manage the 3 hub-owned subnets (private-endpoint-subnet, script-subnet, dataExplorer-subnet) and leave all other subnets in the VNet untouched across upgrades — regardless of what those subnets are used for or what service association links they carry.
Idempotent private networking: Redeploying the template against an existing private hub should result in zero effective changes to the VNet, NSG rules, DNS zones, and private endpoints if the configuration has not changed — no recreation, no connectivity disruption.
Upgrade-aware deployment: Ideally, the template (or upgrade documentation) should explicitly call out the safe upgrade path for private hub deployments, including any parameters that must match the existing deployment exactly (e.g. virtualNetworkAddressPrefix).
📷 Screenshots
TODO: If applicable, add screenshots to help explain your problem. Remove if not applicable.
🔧 Environment
TODO: Complete the following (remove any that are not applicable):
- FinOps hub version: 12.0 to 14.0 upgrade
- Billing account type: MCA (Microsoft Customer Agreement)
- Power BI report type: ADX (Azure Data Explorer)
- Private networking:: Enabled (enablePublicAccess: false)
- Custom subnet:: pbi-network-data-gw-subnet delegated to Microsoft.PowerPlatform/vnetaccesslinks — added post-deployment for Power BI Gateway VNet integration with ADX
ℹ️ Additional context
Root cause — subnet deletion:
In modules/Microsoft.FinOpsHubs/Core/infrastructure.bicep, the VNet is declared with an inline subnets: array:
resource vNet 'Microsoft.Network/virtualNetworks@2023-11-01' = if (hub.options.privateRouting) {
properties: {
addressSpace: { addressPrefixes: [hub.options.networkAddressPrefix] }
subnets: subnets // ARM deletes any subnet not declared here
}
}
When ARM PUTs a VNet with an inline subnets array, it reconciles the complete subnet list and removes any subnet not in the template.
Proposed fix — standalone subnet child resources:
Remove subnets: from the VNet resource and declare each hub subnet as an independent Microsoft.Network/virtualNetworks/subnets resource. ARM only manages explicitly declared child resources, leaving all others untouched:
resource vNet 'Microsoft.Network/virtualNetworks@2023-11-01' = if (hub.options.privateRouting) {
properties: {
addressSpace: { addressPrefixes: [hub.options.networkAddressPrefix] }
// No subnets property — managed as standalone child resources below
}
}
resource finopsHubSubnet 'Microsoft.Network/virtualNetworks/subnets@2023-11-01' = if (hub.options.privateRouting) {
parent: vNet
name: 'private-endpoint-subnet'
...
}
// Repeat for script-subnet and dataExplorer-subnet, chained with dependsOn
// to avoid "concurrent subnet modification" ARM errors
Broader upgrade hardening needed:
Document the required parameters for upgrade vs. fresh deployment (especially virtualNetworkAddressPrefix must match exactly)
Consider adding upgrade documentation/script that validates existing VNet configuration before deploying
Consider detecting existing private networking resources and skipping recreation of already-healthy DNS zones and private endpoints
🙋♀️ Ask for the community
We could use your help:
- Please vote this issue up (👍) to prioritize it.
- Leave comments to help us solidify the vision — especially if you have other private networking resources (Bastion, peered spokes, custom route tables) attached to the FinOps hub VNet that were impacted.
- If you have applied the standalone-subnet workaround in your environment, share your experience in the comments.
🐛 Problem
Upgrading FinOps hub with private networking enabled (enablePublicAccess: false) is destructive to the existing network configuration. The template does not account for an already-deployed private hub and attempts to re-create or reconcile VNet and subnet resources as if performing a fresh deployment. This breaks existing private networking in two ways:
Issue 1 — Subnet deletion: The template defines the 3 hub subnets inline inside the Microsoft.Network/virtualNetworks resource (subnets: [...]). ARM treats this inline list as the complete desired state and attempts to delete any subnet not in the list. This breaks user-added subnets (e.g. a Power BI Gateway subnet with a Microsoft.PowerPlatform/vnetaccesslinks service association link), causing the deployment to fail with InUseSubnetCannotBeDeleted.
Issue 2 — No upgrade-safe path for existing private networking: Even when the subnet error is avoided, the upgrade redeploys all private networking infrastructure (NSG, VNet, DNS zones, private endpoints) without any mechanism to detect or preserve existing configurations, putting connectivity for dependent services (Power BI Gateway, ADX client connections, peered spoke VNets) at risk during deployment.
👣 Repro steps
🤔 Expected
Hub upgrades should be fully non-destructive to existing private networking:
Subnet preservation: The template should only manage the 3 hub-owned subnets (private-endpoint-subnet, script-subnet, dataExplorer-subnet) and leave all other subnets in the VNet untouched across upgrades — regardless of what those subnets are used for or what service association links they carry.
Idempotent private networking: Redeploying the template against an existing private hub should result in zero effective changes to the VNet, NSG rules, DNS zones, and private endpoints if the configuration has not changed — no recreation, no connectivity disruption.
Upgrade-aware deployment: Ideally, the template (or upgrade documentation) should explicitly call out the safe upgrade path for private hub deployments, including any parameters that must match the existing deployment exactly (e.g. virtualNetworkAddressPrefix).
📷 Screenshots
TODO: If applicable, add screenshots to help explain your problem. Remove if not applicable.
🔧 Environment
TODO: Complete the following (remove any that are not applicable):
ℹ️ Additional context
Root cause — subnet deletion:
In modules/Microsoft.FinOpsHubs/Core/infrastructure.bicep, the VNet is declared with an inline subnets: array:
When ARM PUTs a VNet with an inline subnets array, it reconciles the complete subnet list and removes any subnet not in the template.
Proposed fix — standalone subnet child resources:
Remove subnets: from the VNet resource and declare each hub subnet as an independent Microsoft.Network/virtualNetworks/subnets resource. ARM only manages explicitly declared child resources, leaving all others untouched:
Broader upgrade hardening needed:
Document the required parameters for upgrade vs. fresh deployment (especially virtualNetworkAddressPrefix must match exactly)
Consider adding upgrade documentation/script that validates existing VNet configuration before deploying
Consider detecting existing private networking resources and skipping recreation of already-healthy DNS zones and private endpoints
🙋♀️ Ask for the community
We could use your help: