BYO-Vnet - #2269
Conversation
…ment in enterprise environments
…or private networking
- Changed the date in the FinOps hub template from 08/11/2026 to 08/12/2026. - Enhanced the parameters in the FinOps hub template to include detailed descriptions for private endpoint subnet names, NAT Gateway deployment, and private DNS zone creation. - Updated the conditions for creating private DNS zone groups in the deployment JSON to ensure they are only created when necessary. - Added new parameters for subnet names and NAT Gateway options in the Bicep templates, ensuring they are properly utilized in the hub deployment. - Refactored the hub types and internal functions to accommodate the new parameters and improve clarity on private routing configurations.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds bring-your-own virtual network (BYO VNet) support for private routing in FinOps hubs, including configurable subnet names and optional private DNS zone creation for enterprise DNS setups.
Changes:
- Introduces
virtualNetworkMode(new/existing) andexistingVirtualNetworkResourceIdto support existing VNets. - Adds configurable subnet name parameters for private endpoints, scripts, and Data Explorer.
- Adds
createPrivateDnsZonesand gates private DNS zone + zone-group resources accordingly.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/templates/finops-hub/modules/hub.bicep | Adds new networking parameters and passes them into hub construction. |
| src/templates/finops-hub/modules/fx/hub-types.bicep | Extends hub types/config with network mode, subnet names, DNS toggle, and resolves subnet/VNet IDs for new vs existing modes. |
| src/templates/finops-hub/modules/fx/hub-app.bicep | Gates private DNS zone and zone-group resources behind createPrivateDnsZones. |
| src/templates/finops-hub/modules/Microsoft.FinOpsHubs/Core/infrastructure.bicep | Creates VNet only in new mode, adjusts subnet naming, NAT, DNS dependencies, and outputs for existing mode. |
| src/templates/finops-hub/modules/Microsoft.FinOpsHubs/Analytics/app.bicep | Gates private DNS zone resources/groups behind createPrivateDnsZones. |
| src/templates/finops-hub/main.bicep | Exposes/passes through new networking parameters to the hub module. |
| src/templates/finops-hub/createUiDefinition.json | Adds UI fields for subnet names/mode/DNS toggle/existing VNet ID and updates visibility rules. |
| docs/hubs.md | Updates guidance to mention new vs existing VNet options for private networking. |
| docs/deploy/finops-hub-latest.json | Updates generated ARM conditions to honor createPrivateDnsZones. |
| docs-mslearn/toolkit/hubs/template.md | Documents new parameters and subnet usage under private access. |
| docs-mslearn/toolkit/hubs/private-networking.md | Adds detailed guidance for new vs existing VNet mode and BYO subnet requirements. |
| docs-mslearn/toolkit/changelog.md | Notes BYO VNet support, configurable subnets, and createPrivateDnsZones. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| "name": "virtualNetworkMode", | ||
| "type": "Microsoft.Common.DropDown", | ||
| "label": "Virtual network mode", | ||
| "toolTip": "Choose whether FinOps hubs should create a new virtual network and subnets or use an existing virtual network.", | ||
| "defaultValue": "New", | ||
| "constraints": { | ||
| "validations": [ | ||
| "allowedValues": [ | ||
| { | ||
| "regex": "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\/([8-9]|1[0-9]|2[0-6])$", | ||
| "message": "Address prefix must be a valid IPv4 address in the format 'XXX.XXX.XXX.XXX/YY' where YY is between 8 and 26 (minimum /26 subnet size required)." | ||
| "label": "New", | ||
| "description": "Create a new virtual network and subnets.", | ||
| "value": "new" | ||
| }, | ||
| { | ||
| "label": "Existing", | ||
| "description": "Use an existing virtual network and existing subnets.", | ||
| "value": "existing" | ||
| } | ||
| ] | ||
| }, |
| // cSpell:ignore privatelink | ||
| func dnsZoneIdName(type string) IdNameObject => idName('privatelink.${type}.${environment().suffixes.storage}', 'Microsoft.Network/privateDnsZones') | ||
|
|
||
| func resolvedNetworkId(enablePublicAccess bool, virtualNetworkMode string, existingVirtualNetworkResourceId string, networkName string) string => enablePublicAccess ? '' : (virtualNetworkMode == 'existing' ? existingVirtualNetworkResourceId : resourceId('Microsoft.Network/virtualNetworks', networkName)) |
| networkId: resolvedNetworkId(enablePublicAccess, virtualNetworkMode, existingVirtualNetworkResourceId, networkName) | ||
| networkName: enablePublicAccess ? '' : last(split(resolvedNetworkId(enablePublicAccess, virtualNetworkMode, existingVirtualNetworkResourceId, networkName), '/')) |
| dataExplorer: enablePublicAccess ? '' : '${resolvedNetworkId(enablePublicAccess, virtualNetworkMode, existingVirtualNetworkResourceId, networkName)}/subnets/${dataExplorerSubnetName}' | ||
| dataFactory: enablePublicAccess ? '' : '${resolvedNetworkId(enablePublicAccess, virtualNetworkMode, existingVirtualNetworkResourceId, networkName)}/subnets/${privateEndpointSubnetName}' | ||
| keyVault: enablePublicAccess ? '' : '${resolvedNetworkId(enablePublicAccess, virtualNetworkMode, existingVirtualNetworkResourceId, networkName)}/subnets/${privateEndpointSubnetName}' | ||
| scripts: enablePublicAccess ? '' : '${resolvedNetworkId(enablePublicAccess, virtualNetworkMode, existingVirtualNetworkResourceId, networkName)}/subnets/${scriptSubnetName}' | ||
| storage: enablePublicAccess ? '' : '${resolvedNetworkId(enablePublicAccess, virtualNetworkMode, existingVirtualNetworkResourceId, networkName)}/subnets/${privateEndpointSubnetName}' |
|
Thank you for the work on this and for validating the deployment scenario. After reviewing the scope, I don't think we should add support for deploying FinOps hubs into a customer-managed virtual network. The ownership boundary is important for us: the FinOps Toolkit needs to exclusively create and manage the FinOps hub virtual network, its three subnets, private DNS, routing, and related resources so deployments and upgrades remain deterministic. Supporting an existing VNet would make customer-specific subnet delegation, NSGs, routes, egress, DNS, permissions, and lifecycle behavior part of the product support matrix. We do not want to take on that support contract. For customers that require private access from an existing network, the recommended architecture is:
This keeps customer networking under customer ownership without allowing external resources or configuration inside the Toolkit-managed VNet. We captured this intended ownership model and customer-private-endpoint architecture in #2230, related to #2156. That documentation PR was closed rather than merged, so the guidance still needs to be landed separately; we should correct that documentation gap rather than add BYO-VNet support here. This is a product-scope decision rather than a request to revise the implementation. My recommendation is to close this PR and #2268 as not planned. Thank you again for the contribution and for surfacing the enterprise networking requirement. |
🛠️ Description
Adds bring-your-own virtual network support for FinOps hubs using private networking. The deployment can now use an existing VNet and subnets, configure subnet delegation and private endpoint networking, optionally deploy a NAT Gateway for controlled outbound access, and optionally create private DNS zones for centralized DNS scenarios.
Fixes #2268
📷 Screenshots
Not applicable. This change updates the deployment experience and infrastructure configuration.
📋 Checklist
🔬 How did you test this change?
📦 Deploy to test?
🙋♀️ Do any of the following that apply?
📑 Did you update
docs/changelog.md?📖 Did you update documentation?