Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions docs/deploy/finops-hub-latest.ui.json
Original file line number Diff line number Diff line change
Expand Up @@ -890,33 +890,52 @@
"label": "Networking",
"elements": [
{
"name": "infraEncryptionIntro",
"name": "networkingIntro",
"type": "Microsoft.Common.TextBlock",
"visible": true,
"options": {
"text": "For enhanced security, consider blocking external access to your FinOps hub instance to enable secure, private connectivity to your cloud resources by eliminating exposure to the public internet. Private endpoints can incur significant additional cost. Please understand the cost impact before selecting this option."
"text": "Select the network isolation mode. Private vNet uses private endpoints to block all public access and incurs significant additional cost (private endpoint hours, data processing, plus a NAT Gateway with a public IP for outbound dependencies). Please understand the cost impact before selecting Private vNet."
}
},
{
"name": "enablePublicAccess",
"type": "Microsoft.Common.DropDown",
"label": "Access",
"toolTip": "Indicate whether FinOps hubs resources should be accessible by the internet or not. If set to private, all resources will be hidden behind a virtual network private endpoint. This will incur additional costs for data crossing virtual network boundaries and for virtual network peering, if configured.",
"defaultValue": "Public",
"multiLine": true,
"name": "networkMode",
"type": "Microsoft.Common.OptionsGroup",
"label": "Network access mode",
"defaultValue": "Public (no vNet)",
"toolTip": "Choose how FinOps hubs resources are exposed on the network. Public: no virtual network, all resources reachable from the internet. vNet: deploy resources inside a virtual network with a NAT Gateway for outbound traffic, but keep public endpoints (segmentation without private-endpoint cost). Private vNet: all resources are hidden behind private endpoints; public access is blocked. This will incur additional costs for private endpoints, data processing across virtual network boundaries, and for virtual network peering if configured.",
"constraints": {
"allowedValues": [
{
"label": "Public",
"description": "Allow external access to storage and Data Explorer.",
"value": true
"label": "Public (no vNet)",
"value": "public"
},
{
"label": "vNet (public endpoints)",
"value": "vnet"
},
{
"label": "Private",
"description": "Block all external access. This will incur additional charges.",
"value": false
"label": "Private vNet (private endpoints only)",
"value": "private"
}
]
],
"required": true
},
"visible": true
},
{
"name": "vnetModeNote",
"type": "Microsoft.Common.TextBlock",
"visible": "[equals(steps('advanced').networking.networkMode, 'vnet')]",
"options": {
"text": "A virtual network + NSG + 3 subnets are deployed as a scaffold for future expansion, but public endpoints remain. No NAT Gateway and no private endpoints are created, so this mode adds no Azure cost beyond the free VNet primitives. Useful if you want a VNet ready to flip to Private vNet later without recreating resources."
}
},
{
"name": "privateModeNote",
"type": "Microsoft.Common.TextBlock",
"visible": "[equals(steps('advanced').networking.networkMode, 'private')]",
"options": {
"text": "Private endpoints and private DNS zones will be created for storage, Key Vault, and Data Explorer. A NAT Gateway with a static public IP is also deployed so deployment scripts and Data Explorer can reach Microsoft Container Registry and the FinOps toolkit open data on GitHub. This incurs charges for private endpoint hours, data processing, NAT Gateway hours, and the public IP. Switching back to vNet or Public later does NOT delete these resources — clean them up manually if you downgrade."
}
},
{
Expand All @@ -933,7 +952,7 @@
}
]
},
"visible": "[equals(steps('advanced').networking.enablePublicAccess, false)]"
"visible": "[not(equals(steps('advanced').networking.networkMode, 'public'))]"
}
],
"visible": true
Expand All @@ -954,9 +973,13 @@
"Microsoft.KeyVault/vaults",
"Microsoft.Kusto/clusters",
"Microsoft.ManagedIdentity/userAssignedIdentities",
"Microsoft.Network/natGateways",
"Microsoft.Network/networkSecurityGroups",
"Microsoft.Network/privateDnsZones",
"Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"Microsoft.Network/privateEndpoints",
"Microsoft.Network/publicIPAddresses",
"Microsoft.Network/virtualNetworks",
"Microsoft.Resources/deploymentScripts",
"Microsoft.Storage/storageAccounts"
]
Expand All @@ -976,7 +999,8 @@
"enableRecommendations": "[steps('recommendations').enableRecommendations]",
"enableAHBRecommendations": "[steps('recommendations').optional.enableAHBRecommendations]",
"enableSpotRecommendations": "[steps('recommendations').optional.enableSpotRecommendations]",
"enablePublicAccess": "[steps('advanced').networking.enablePublicAccess]",
"enablePublicAccess": "[not(equals(steps('advanced').networking.networkMode, 'private'))]",
"networkMode": "[steps('advanced').networking.networkMode]",
"virtualNetworkAddressPrefix": "[steps('advanced').networking.virtualNetworkAddressPrefix]",
"dataExplorerSku": "[steps('pricing').dataExplorer.dataExplorerSku]",
"exportRetentionInDays": "[steps('retention').storage.msexportsDays]",
Expand Down
58 changes: 41 additions & 17 deletions src/templates/finops-hub/createUiDefinition.json
Original file line number Diff line number Diff line change
Expand Up @@ -906,33 +906,52 @@
"label": "Networking",
"elements": [
{
"name": "infraEncryptionIntro",
"name": "networkingIntro",
"type": "Microsoft.Common.TextBlock",
"visible": true,
"options": {
"text": "For enhanced security, consider blocking external access to your FinOps hub instance to enable secure, private connectivity to your cloud resources by eliminating exposure to the public internet. Private endpoints can incur significant additional cost. Please understand the cost impact before selecting this option."
"text": "Select the network isolation mode. Private vNet uses private endpoints to block all public access and incurs significant additional cost (private endpoint hours, data processing, plus a NAT Gateway with a public IP for outbound dependencies). Please understand the cost impact before selecting Private vNet."
}
},
{
"name": "enablePublicAccess",
"type": "Microsoft.Common.DropDown",
"label": "Access",
"toolTip": "Indicate whether FinOps hubs resources should be accessible by the internet or not. If set to private, all resources will be hidden behind a virtual network private endpoint. This will incur additional costs for data crossing virtual network boundaries and for virtual network peering, if configured.",
"defaultValue": "Public",
"multiLine": true,
"name": "networkMode",
"type": "Microsoft.Common.OptionsGroup",
"label": "Network access mode",
"defaultValue": "Public (no vNet)",
"toolTip": "Choose how FinOps hubs resources are exposed on the network. Public: no virtual network, all resources reachable from the internet. vNet: deploy resources inside a virtual network with a NAT Gateway for outbound traffic, but keep public endpoints (segmentation without private-endpoint cost). Private vNet: all resources are hidden behind private endpoints; public access is blocked. This will incur additional costs for private endpoints, data processing across virtual network boundaries, and for virtual network peering if configured.",
"constraints": {
"allowedValues": [
{
"label": "Public",
"description": "Allow external access to storage and Data Explorer.",
"value": true
"label": "Public (no vNet)",
"value": "public"
},
{
"label": "vNet (public endpoints)",
"value": "vnet"
},
{
"label": "Private",
"description": "Block all external access. This will incur additional charges.",
"value": false
"label": "Private vNet (private endpoints only)",
"value": "private"
}
]
],
"required": true
},
"visible": true
},
{
"name": "vnetModeNote",
"type": "Microsoft.Common.TextBlock",
"visible": "[equals(steps('advanced').networking.networkMode, 'vnet')]",
"options": {
"text": "A virtual network + NSG + 3 subnets are deployed as a scaffold for future expansion, but public endpoints remain. No NAT Gateway and no private endpoints are created, so this mode adds no Azure cost beyond the free VNet primitives. Useful if you want a VNet ready to flip to Private vNet later without recreating resources."
}
},
{
"name": "privateModeNote",
"type": "Microsoft.Common.TextBlock",
"visible": "[equals(steps('advanced').networking.networkMode, 'private')]",
"options": {
"text": "Private endpoints and private DNS zones will be created for storage, Key Vault, and Data Explorer. A NAT Gateway with a static public IP is also deployed so deployment scripts and Data Explorer can reach Microsoft Container Registry and the FinOps toolkit open data on GitHub. This incurs charges for private endpoint hours, data processing, NAT Gateway hours, and the public IP. Switching back to vNet or Public later does NOT delete these resources — clean them up manually if you downgrade."
}
},
{
Expand All @@ -949,7 +968,7 @@
}
]
},
"visible": "[equals(steps('advanced').networking.enablePublicAccess, false)]"
"visible": "[not(equals(steps('advanced').networking.networkMode, 'public'))]"
}
],
"visible": true
Expand All @@ -970,9 +989,13 @@
"Microsoft.KeyVault/vaults",
"Microsoft.Kusto/clusters",
"Microsoft.ManagedIdentity/userAssignedIdentities",
"Microsoft.Network/natGateways",
"Microsoft.Network/networkSecurityGroups",
"Microsoft.Network/privateDnsZones",
"Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"Microsoft.Network/privateEndpoints",
"Microsoft.Network/publicIPAddresses",
"Microsoft.Network/virtualNetworks",
"Microsoft.Resources/deploymentScripts",
"Microsoft.Storage/storageAccounts"
]
Expand All @@ -992,7 +1015,8 @@
"enableRecommendations": "[steps('recommendations').enableRecommendations]",
"enableAHBRecommendations": "[steps('recommendations').optional.enableAHBRecommendations]",
"enableSpotRecommendations": "[steps('recommendations').optional.enableSpotRecommendations]",
"enablePublicAccess": "[steps('advanced').networking.enablePublicAccess]",
"enablePublicAccess": "[not(equals(steps('advanced').networking.networkMode, 'private'))]",
"networkMode": "[steps('advanced').networking.networkMode]",
"virtualNetworkAddressPrefix": "[steps('advanced').networking.virtualNetworkAddressPrefix]",
"dataExplorerSku": "[steps('pricing').dataExplorer.dataExplorerSku]",
"exportRetentionInDays": "[steps('retention').storage.msexportsDays]",
Expand Down
22 changes: 20 additions & 2 deletions src/templates/finops-hub/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,31 @@ param dataExplorerRawRetentionInDays int = 0
@description('Optional. Number of months of data to retain in the Data Explorer *_final_v* tables. Default: 13.')
param dataExplorerFinalRetentionInMonths int = 13

@description('Optional. Enable public access to FinOps hubs resources. Default: true.')
@description('Optional. DEPRECATED — use networkMode instead. Enable public access to FinOps hubs resources. Default: true. Honored only when networkMode is omitted: false maps to "private", true maps to "public". When networkMode is supplied this parameter is ignored.')
param enablePublicAccess bool = true

@description('Optional. Network access mode. "public" (default): no virtual network, all resources publicly reachable. "vnet": virtual network + NSG scaffold deployed for future use, but public endpoints remain; no NAT Gateway, no private endpoints, no extra cost beyond the (free) VNet/NSG. "private": full virtual network with private endpoints, NAT Gateway + static public IP for outbound egress (deployment scripts to MCR and ADX open-data to GitHub), public access blocked. When not specified, derived from enablePublicAccess. NOTE: switching modes does not delete resources from previous modes (incremental deployment); to clean up, manually remove orphaned VNet/NAT/PIP/PE/DNS resources after switching to a lower mode.')
@allowed([
'public'
'vnet'
'private'
])
param networkMode string?

@description('Optional. Address space for the workload. Minimum /26 subnet size is required for the workload. Default: "10.20.30.0/26".')
param virtualNetworkAddressPrefix string = '10.20.30.0/26'


//==============================================================================
// Variables
//==============================================================================

// Resolve networkMode: explicit value wins; otherwise derive from legacy enablePublicAccess.
// !empty() guards against both null AND empty-string inputs (the latter could theoretically arrive
// via templates that pre-existed the @allowed change).
var effectiveNetworkMode = !empty(networkMode) ? networkMode! : (enablePublicAccess ? 'public' : 'private')


//==============================================================================
// Resources
//==============================================================================
Expand Down Expand Up @@ -194,7 +212,7 @@ module hub 'modules/hub.bicep' = {
dataExplorerFinalRetentionInMonths: dataExplorerFinalRetentionInMonths
remoteHubStorageUri: remoteHubStorageUri
remoteHubStorageKey: remoteHubStorageKey
enablePublicAccess: enablePublicAccess
networkMode: effectiveNetworkMode
virtualNetworkAddressPrefix: virtualNetworkAddressPrefix
}
}
Expand Down
Loading