Skip to content

Commit 7ee6dd7

Browse files
msbrettCopilot
andcommitted
feat(finops-hub): PowerShell parity for networkMode + changelog
Adds -NetworkMode parameter to Deploy-FinOpsHub and Deploy-Hub so the new tri-state network model (public|vnet|private) introduced for the Sept 2025 implicit-outbound retirement is reachable from PowerShell, not just the portal UI. Addresses the CHANGES_REQUESTED review on #2163. Deploy-FinOpsHub (cmdlet): - Add -NetworkMode <public|vnet|private> with ValidateSet - Replace stale .PARAMETER EnablePublicAccess help block with accurate .PARAMETER NetworkMode + .PARAMETER DisablePublicAccess (deprecated) - Version-guard the networkMode template parameter for v15.0+ - When -NetworkMode is supplied on v15+, skip enablePublicAccess so the two parameters never go on the wire together (bicep effectiveNetworkMode already lets networkMode win; sending both clutters deployment history) Deploy-Hub.ps1 (dev script): - Add -NetworkMode <public|vnet|private> with ValidateSet - Keep -Private switch as deprecated back-compat alias - -NetworkMode wins when both are supplied infrastructure.bicep: - Add comment noting that in vnet mode all subnets get defaultOutboundAccess:false with no NAT attached -- intentionally egress-less scaffolding for future private-mode upgrades changelog.md: - Document the new networkMode parameter under FinOps hubs v15 Added - Add upgrade-impact note under Changed flagging that existing enablePublicAccess=false deployments will gain a NAT Gateway and Public IP on next deploy (NAT hours + PIP + data processing charges) - Bump ms.date to 06/03/2026 per docs-mslearn rule Verified end-to-end via az deployment group what-if against the built template for all three modes: public: no VNet, no NSG, no NAT (correct) vnet: VNet + NSG only, no NAT (correct) private: VNet + NSG + NAT Gateway + Public IP + PE + DNS zones (correct) Refs #2161 #2163 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent aff09d7 commit 7ee6dd7

4 files changed

Lines changed: 55 additions & 11 deletions

File tree

docs-mslearn/toolkit/changelog.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: FinOps toolkit changelog
33
description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more.
44
author: MSBrett
55
ms.author: brettwil
6-
ms.date: 05/19/2026
6+
ms.date: 06/03/2026
77
ms.topic: reference
88
ms.service: finops
99
ms.subservice: finops-toolkit
@@ -47,8 +47,11 @@ _Released June 2026_
4747

4848
### [FinOps hubs](hubs/finops-hubs-overview.md) v15
4949

50+
- **Added**
51+
- Added tri-state `networkMode` parameter (`public` | `vnet` | `private`) to replace the binary `enablePublicAccess` switch, with corresponding `-NetworkMode` parameters in `Deploy-FinOpsHub` and the `Deploy-Hub` development script. The legacy `enablePublicAccess` parameter and `-DisablePublicAccess` switch are kept for back-compat ([#2163](https://github.com/microsoft/finops-toolkit/pull/2163)).
5052
- **Changed**
5153
- Added a callout to the `config_RunBackfillJob` backfill option clarifying that it isn't supported on Microsoft Customer Agreement (MCA) billing accounts or billing profiles ([#2113](https://github.com/microsoft/finops-toolkit/issues/2113)).
54+
- Set `defaultOutboundAccess: false` on all subnets and added a NAT Gateway + static Public IP in `private` mode so deployments comply with the "Subnets should be private" policy and the September 2025 implicit-outbound retirement. **Upgrade note:** existing hubs deployed with `enablePublicAccess=false` will gain a NAT Gateway and Public IP on next deploy, which adds NAT hours, Public IP, and data-processing charges to the monthly cost ([#2161](https://github.com/microsoft/finops-toolkit/issues/2161)).
5255

5356
<!-- prettier-ignore-start -->
5457
> [!div class="nextstepaction"]

src/powershell/Public/Deploy-FinOpsHub.ps1

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,11 @@
8484
.PARAMETER DataExplorerFinalRetentionInMonths
8585
Optional. Number of months of data to retain in the Data Explorer *_final_v* tables. Default: 13.
8686
87-
.PARAMETER EnablePublicAccess
88-
Optional. Enable public access to the data lake. Default: true.
87+
.PARAMETER NetworkMode
88+
Optional. Network access mode for the hub. Allowed: "public" (default — no virtual network, all resources publicly reachable), "vnet" (virtual network + NSG scaffold for future use, public endpoints remain), "private" (full virtual network with private endpoints and NAT Gateway + static public IP for outbound egress). When specified, takes precedence over -DisablePublicAccess. Requires hub template v15.0 or later. Default: not set (template falls back to -DisablePublicAccess for older templates, or "public" when neither is supplied).
89+
90+
.PARAMETER DisablePublicAccess
91+
Optional. DEPRECATED — use -NetworkMode instead. Disable public access to the data lake. When -NetworkMode is also supplied, -NetworkMode wins. Default: false.
8992
9093
.PARAMETER VirtualNetworkAddressPrefix
9194
Optional. Address space for the workload. A /26 is required for the workload. Default: "10.20.30.0/26".
@@ -187,6 +190,11 @@ function Deploy-FinOpsHub
187190
[int]
188191
$DataExplorerFinalRetentionInMonths = 13,
189192

193+
[Parameter()]
194+
[ValidateSet('public', 'vnet', 'private')]
195+
[string]
196+
$NetworkMode,
197+
190198
[Parameter()]
191199
[switch]
192200
$DisablePublicAccess,
@@ -281,7 +289,13 @@ function Deploy-FinOpsHub
281289
$parameterSplat.TemplateParameterObject.Add('dataExplorerCapacity', $DataExplorerCapacity)
282290
$parameterSplat.TemplateParameterObject.Add('dataExplorerRawRetentionInDays', $DataExplorerRawRetentionInDays)
283291
$parameterSplat.TemplateParameterObject.Add('dataExplorerFinalRetentionInMonths', $DataExplorerFinalRetentionInMonths)
284-
$parameterSplat.TemplateParameterObject.Add('enablePublicAccess', -not $DisablePublicAccess)
292+
# networkMode (v15+) wins over enablePublicAccess; only send the legacy parameter
293+
# when -NetworkMode wasn't supplied or the template is older than v15.0.
294+
$useNetworkMode = $PSBoundParameters.ContainsKey('NetworkMode') -and ($Version -eq 'latest' -or [version]$Version -ge '15.0')
295+
if (-not $useNetworkMode)
296+
{
297+
$parameterSplat.TemplateParameterObject.Add('enablePublicAccess', -not $DisablePublicAccess)
298+
}
285299
$parameterSplat.TemplateParameterObject.Add('virtualNetworkAddressPrefix', $VirtualNetworkAddressPrefix)
286300
$parameterSplat.TemplateParameterObject.Add('exportRetentionInDays', $ExportRetentionInDays)
287301
$parameterSplat.TemplateParameterObject.Add('ingestionRetentionInMonths', $IngestionRetentionInMonths)
@@ -299,6 +313,11 @@ function Deploy-FinOpsHub
299313
$parameterSplat.TemplateParameterObject.Add('enableManagedExports', $EnableManagedExports.IsPresent)
300314
}
301315

316+
if (($Version -eq 'latest' -or [version]$Version -ge '15.0') -and $PSBoundParameters.ContainsKey('NetworkMode'))
317+
{
318+
$parameterSplat.TemplateParameterObject.Add('networkMode', $NetworkMode)
319+
}
320+
302321
if ($Version -eq 'latest' -or [version]$Version -ge '13.0')
303322
{
304323
$parameterSplat.TemplateParameterObject.Add('enablePurgeProtection', $EnablePurgeProtection.IsPresent)

src/scripts/Deploy-Hub.ps1

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,14 @@
8888
.PARAMETER ManagedExports
8989
Optional. Use managed exports instead of manual exports. Requires -Scope. Grants the hub managed identity the required roles on the scope and passes scopesToMonitor to the template.
9090
91+
.PARAMETER NetworkMode
92+
Optional. Network access mode. Allowed: "public" (no VNet), "vnet" (VNet + NSG scaffold, public endpoints remain), "private" (VNet + private endpoints + NAT Gateway). Takes precedence over -Private. Requires hub template v15 or later. Default: not set.
93+
9194
.PARAMETER Private
92-
Optional. Deploy with private networking (VNet and private endpoints). Default: false.
95+
Optional. DEPRECATED — use -NetworkMode private instead. Deploy with private networking (VNet and private endpoints). Default: false.
9396
9497
.PARAMETER VirtualNetworkAddressPrefix
95-
Optional. Virtual network address prefix for private networking. Requires a /26 CIDR block. When set, also sets -Private. Default: "10.20.30.0/26".
98+
Optional. Virtual network address prefix for private networking. Requires a /26 CIDR block. When set, also enables private mode. Default: "10.20.30.0/26".
9699
97100
.PARAMETER Build
98101
Optional. Build the template before deploying.
@@ -116,6 +119,8 @@ param(
116119
[switch]$Remove,
117120
[string]$Scope,
118121
[switch]$ManagedExports,
122+
[ValidateSet('public', 'vnet', 'private')]
123+
[string]$NetworkMode,
119124
[switch]$Private,
120125
[string]$VirtualNetworkAddressPrefix,
121126
[string]$Location,
@@ -283,16 +288,30 @@ else
283288
$params.enableManagedExports = $false
284289
}
285290

286-
# Private networking (infer from VNet prefix if provided)
287-
if ($VirtualNetworkAddressPrefix) { $Private = $true }
288-
if ($Private)
291+
# Network mode (preferred) / private networking back-compat
292+
# -NetworkMode wins over -Private. -VirtualNetworkAddressPrefix implies private mode when
293+
# neither -NetworkMode nor -Private is set.
294+
if ($NetworkMode)
289295
{
290-
$params.enablePublicAccess = $false
296+
$params.networkMode = $NetworkMode
291297
if ($VirtualNetworkAddressPrefix)
292298
{
293299
$params.virtualNetworkAddressPrefix = $VirtualNetworkAddressPrefix
294300
}
295-
Write-Host " Private networking: enabled (VNet $($VirtualNetworkAddressPrefix ?? '10.20.30.0/26'))"
301+
Write-Host " Network mode: $NetworkMode$(if ($NetworkMode -ne 'public') { " (VNet $($VirtualNetworkAddressPrefix ?? '10.20.30.0/26'))" })"
302+
}
303+
else
304+
{
305+
if ($VirtualNetworkAddressPrefix) { $Private = $true }
306+
if ($Private)
307+
{
308+
$params.enablePublicAccess = $false
309+
if ($VirtualNetworkAddressPrefix)
310+
{
311+
$params.virtualNetworkAddressPrefix = $VirtualNetworkAddressPrefix
312+
}
313+
Write-Host " Private networking: enabled (VNet $($VirtualNetworkAddressPrefix ?? '10.20.30.0/26'))"
314+
}
296315
}
297316

298317
# Resource group

src/templates/finops-hub/modules/Microsoft.FinOpsHubs/Core/infrastructure.bicep

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ var finopsHubSubnetName = 'private-endpoint-subnet'
2525
var scriptSubnetName = 'script-subnet'
2626
var dataExplorerSubnetName = 'dataExplorer-subnet'
2727

28+
// In vnet mode, all subnets are deployed with defaultOutboundAccess:false but no NAT Gateway
29+
// is attached — they are intentionally egress-less scaffolding for future private-mode upgrades.
30+
// NAT Gateway is only attached to script + dataExplorer subnets when privateRouting is enabled.
2831
var subnets = !hub.options.vnetIntegration ? [] : [
2932
{
3033
name: finopsHubSubnetName

0 commit comments

Comments
 (0)