Skip to content

feat(finops-hub): Add sovereign cloud support#2072

Open
MSBrett wants to merge 3 commits intodevfrom
features/fix-gov-cloud-suffixes
Open

feat(finops-hub): Add sovereign cloud support#2072
MSBrett wants to merge 3 commits intodevfrom
features/fix-gov-cloud-suffixes

Conversation

@MSBrett
Copy link
Copy Markdown
Contributor

@MSBrett MSBrett commented Mar 27, 2026

Summary

Adds sovereign cloud support to FinOps Hubs, enabling deployment to Azure US Government, Azure China (21Vianet), and other sovereign environments.

Changes

Bicep template changes (src/templates/finops-hub/)

  • Kusto DNS suffix: Replace hardcoded .kusto.windows.net with an environment-aware lookup map covering AzureCloud, AzureUSGovernment, and AzureChinaCloud, with a replace() fallback heuristic for unknown clouds. Fixes an incorrect China suffix (kusto.chinacloudapi.cnkusto.windows.cn).
  • Open data URL: Add openDataBaseUrl parameter (threaded through main.bicephub.bicepAnalytics/app.bicep) so sovereign environments without internet access can point to a local storage account instead of GitHub.
  • Conditional ADF resources: Automatically skip ADF GitHub linked service and dataset when openDataBaseUrl points to the hub's own storage account.
  • Storage URL validation: Update createUiDefinition.json regex to accept storage suffixes from all clouds (not just .windows.net).
  • Dashboard portal links: Replace 27 hardcoded portal.azure.com URLs in dashboard.json with a build-time $$defined-portal-url$$ token.
  • Dashboard cluster URI: Clear the hardcoded clusterUri — users configure it to their cluster after import.
  • Build script: Add -PortalUrl parameter to Build-Toolkit.ps1 (defaults to https://portal.azure.com).
  • Bug fix: Fix gitapp.hub.com typo in ADF linked service URL → github.com.

Documentation (docs-mslearn/toolkit/hubs/)

  • deploy-sovereign.md: New Microsoft Learn how-to guide covering build, open-data preparation, deployment, and dashboard configuration for sovereign clouds. Follows deploy.md conventions (front matter, tab selectors, admonitions, related content).

Testing

  • Bicep compiles clean (bicep build main.bicep)
  • JSON validity verified
  • Grep verification: no hardcoded .kusto.windows.net, portal.azure.com, logic.azure.com, or gitapp.hub.com in changed files
  • Red-team audit: all DNS suffix claims verified against Azure Private Link DNS zone docs
  • Blue-team validation: all code assertions verified against repo files
  • ❎ Log not needed

Checklist

  • Bicep changes scoped to src/templates/finops-hub/ only
  • No changes to PowerShell module, Optimization Engine, or other templates
  • Documentation follows Microsoft style guide (sentence casing, active voice, no end punctuation on headings)
  • deploy-sovereign.md matches deploy.md format conventions

msbrett and others added 2 commits March 26, 2026 16:18
- Replace hardcoded .kusto.windows.net with environment-aware lookup map
  covering AzureCloud, AzureUSGovernment, AzureChinaCloud with fallback
  heuristic for unknown clouds
- Fix China ADX suffix: kusto.windows.cn (not kusto.chinacloudapi.cn)
- Add openDataBaseUrl parameter for sovereign open-data ingestion
  (main.bicep → hub.bicep → Analytics/app.bicep)
- Auto-skip ADF GitHub resources when open data is local storage
- Fix createUiDefinition regex to accept all cloud storage suffixes
- Replace 27 hardcoded portal.azure.com URLs in dashboard.json with
  build-time variable token
- Add -PortalUrl parameter to Build-Toolkit.ps1
- Clear hardcoded clusterUri in dashboard.json (user configures post-import)
- Fix gitapp.hub.com typo in ADF linked service URL
- Add SOVEREIGN-CLOUD-GUIDE.md: deployment workflow, suffix inventory,
  prerequisites, verified against Microsoft Learn docs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add deploy-sovereign.md: Microsoft Learn how-to guide for sovereign
  cloud deployments (US Government, China, other sovereign environments)
- deploy-sovereign.md follows deploy.md conventions: front matter,
  tab selectors, admonitions, nextstepaction blocks, related content

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Review 👀 PR that is ready to be reviewed label Mar 27, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Data Explorer SKU and retention settings are now only visible when Azure Data Explorer mode is selected.
- Added typed metadata contracts between hub apps to formalize dependency management and enable compile-time verification of inter-app interfaces.
- **Added**
- Added sovereign cloud deployment support for Azure US Government, Azure China (21Vianet), and other sovereign environments ([#2072](https://github.com/microsoft/finops-toolkit/pull/2072)).
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Added sovereign cloud deployment support for Azure US Government, Azure China (21Vianet), and other sovereign environments ([#2072](https://github.com/microsoft/finops-toolkit/pull/2072)).
- Added sovereign cloud deployment support for Azure Government, Azure China, and other [Microsoft Sovereign Cloud](/industry/sovereign-cloud/overview/microsoft-sovereign-cloud) environments ([#2072](https://github.com/microsoft/finops-toolkit/pull/2072)).

- Remote Hub configuration (storage URI, storage key, and purge protection) is now displayed in the Basics tab when Remote Hub mode is selected, making the mutual exclusivity clear.
- Data Explorer SKU and retention settings are now only visible when Azure Data Explorer mode is selected.
- Added typed metadata contracts between hub apps to formalize dependency management and enable compile-time verification of inter-app interfaces.
- **Added**
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added should go above Changed


# How to deploy FinOps hubs to sovereign clouds

This article explains how to deploy FinOps hubs to sovereign Azure clouds, including Azure US Government, Azure China (21Vianet), and other sovereign environments. Bicep's `environment()` function compiles to an ARM runtime expression that resolves in the target cloud, so templates built on any workstation deploy correctly to any cloud. No cross-compilation is needed. This article helps you:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aligning to official terms...

Suggested change
This article explains how to deploy FinOps hubs to sovereign Azure clouds, including Azure US Government, Azure China (21Vianet), and other sovereign environments. Bicep's `environment()` function compiles to an ARM runtime expression that resolves in the target cloud, so templates built on any workstation deploy correctly to any cloud. No cross-compilation is needed. This article helps you:
This article explains how to deploy FinOps hubs to [Microsoft Sovereign Clouds](/industry/sovereign-cloud/overview/microsoft-sovereign-cloud), including Azure Government, Azure China, and other sovereign environments. Bicep's `environment()` function compiles to an ARM runtime expression that resolves in the target cloud, so templates built on any workstation deploy correctly to any cloud. No cross-compilation is needed. This article helps you:


# How to deploy FinOps hubs to sovereign clouds

This article explains how to deploy FinOps hubs to sovereign Azure clouds, including Azure US Government, Azure China (21Vianet), and other sovereign environments. Bicep's `environment()` function compiles to an ARM runtime expression that resolves in the target cloud, so templates built on any workstation deploy correctly to any cloud. No cross-compilation is needed. This article helps you:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this is end user documentation, I don't think we need to call out the Bicep caveat.

Comment on lines +50 to +55
| Cloud | Environment name | Portal URL | Status |
|-------|-----------------|------------|--------|
| Azure Commercial | `AzureCloud` | `portal.azure.com` | ✅ Fully supported |
| Azure US Government | `AzureUSGovernment` | `portal.azure.us` | ✅ Fully supported |
| Azure China (21Vianet) | `AzureChinaCloud` | `portal.azure.cn` | ✅ Fully supported |
| Other sovereign clouds | *(verify with your environment)* | *(verify with your environment)* | ⚠️ Supported with parameter overrides |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the system of record for "Environment name"? We don't include "US" in Azure Gov, so I'm questioning that column. What is the purpose of that column at all? How will it be used? I would recomment getting rid of it unless we explicitly need it.

Suggested change
| Cloud | Environment name | Portal URL | Status |
|-------|-----------------|------------|--------|
| Azure Commercial | `AzureCloud` | `portal.azure.com` | ✅ Fully supported |
| Azure US Government | `AzureUSGovernment` | `portal.azure.us` | ✅ Fully supported |
| Azure China (21Vianet) | `AzureChinaCloud` | `portal.azure.cn` | ✅ Fully supported |
| Other sovereign clouds | *(verify with your environment)* | *(verify with your environment)* | ⚠️ Supported with parameter overrides |
| Cloud | Portal URL | Status |
|-------|------------|--------|
| Azure Commercial | `portal.azure.com` | ✅ Fully supported |
| Azure Government | `portal.azure.us` | ✅ Fully supported |
| Azure China | `portal.azure.cn` | ✅ Fully supported |
| Others | *(verify with your environment)* | ⚠️ Supported with parameter overrides |

Fwiw, I don't actually know what value this table brings. Everything is supported the same way, right?

Comment on lines +129 to +132
@description('Optional. Base URL to use for FinOps Toolkit open data CSV files. Override this to point to a hub storage path when the CSV files are pre-loaded into the hub storage account. Default: The current FinOps Toolkit GitHub open-data path for this build.')
param openDataBaseUrl string = contains(loadTextContent('modules/fx/ftkver.txt'), '-dev')
? 'https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/heads/dev/src/open-data'
: 'https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/tags/${loadTextContent('modules/fx/ftktag.txt')}/src/open-data'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's simplify this. If we want to offer deploying to storage, then let's just make that a boolean. This just makes it more difficult to set it up by requiring people to find the URL.

Comment on lines +129 to +132
@description('Optional. Base URL to use for FinOps Toolkit open data CSV files. Override this to point to a hub storage path when the CSV files are pre-loaded into the hub storage account. Default: The current FinOps Toolkit GitHub open-data path for this build.')
param openDataBaseUrl string = contains(loadTextContent('modules/fx/ftkver.txt'), '-dev')
? 'https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/heads/dev/src/open-data'
: 'https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/tags/${loadTextContent('modules/fx/ftktag.txt')}/src/open-data'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roland has raise a concern about how these files aren't getting updated over time. We should consider that before we make a substantive change to how we ingest the data to ensure we're accounting for keeping them updated for people. Maybe a separate deployment/app?

// GitHub repository linked service for FTK open data
resource linkedService_ftkRepo 'Microsoft.DataFactory/factories/linkedservices@2018-06-01' = {
// GitHub repository linked service for FTK release files
resource linkedService_ftkRepo 'Microsoft.DataFactory/factories/linkedservices@2018-06-01' = if (!useLocalOpenData) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just always push the files to storage rather than using GitHub as the source? I prefer not from a cost perspective, but that would simplify this by only offering one approach.

- **Added**
- Added sovereign cloud deployment support for Azure US Government, Azure China (21Vianet), and other sovereign environments ([#2072](https://github.com/microsoft/finops-toolkit/pull/2072)).
- Added `openDataBaseUrl` parameter to support open-data ingestion from a local storage account in sovereign environments without internet access.
- Added `-PortalUrl` parameter to `Build-Toolkit.ps1` for sovereign cloud dashboard feedback links.
Copy link
Copy Markdown
Collaborator

@flanakin flanakin Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Do internal build script changes go into the changelog? 🤔 Not opposed to it. But it's a level of detail our customers generally shouldn't need.

Comment on lines +61 to +62
- Fixed incorrect China ADX DNS suffix derivation (`kusto.chinacloudapi.cn` → `kusto.windows.cn`).
- Fixed `createUiDefinition.json` storage URL validation to accept all cloud storage suffixes.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, these changes sound like AI fixes within the PR, not fixing something that was already there.

Suggested change
- Fixed incorrect China ADX DNS suffix derivation (`kusto.chinacloudapi.cn``kusto.windows.cn`).
- Fixed `createUiDefinition.json` storage URL validation to accept all cloud storage suffixes.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Attention 👋 Issue or PR needs to be reviewed by the author or it will be closed due to no activity and removed Needs: Review 👀 PR that is ready to be reviewed labels Mar 27, 2026
@microsoft-github-policy-service
Copy link
Copy Markdown

@@MSBrett: you have some new feedback!

Please review and resolve all comments and I'll let reviewers know by removing the Needs: Attention label. If I miss anything, just reply with #needs-review and I'll update the status.

Copy link
Copy Markdown
Collaborator

@flanakin flanakin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] PR Review

Summary: Well-structured sovereign cloud support with clean Kusto DNS suffix handling, proper conditional resource deployment, and thorough documentation. One minor suggestion below.

💡 Suggestions (1)

  1. ftkGitTag variable is now only consumed by the conditional dataset_ftkReleaseFile resource — consider adding a comment noting this dependency.

@@ -135,15 +140,22 @@ var HUB_DB = 'Hub'
var INGESTION_DB = 'Ingestion'

var ftkGitTag = loadTextContent('../../fx/ftktag.txt') // cSpell:ignore ftktag
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] 💡 Suggestion

With the ftkReleaseUri refactor, ftkGitTag is now only consumed by dataset_ftkReleaseFile (line 667), which is gated behind !useLocalOpenData. When deploying with local open data, this variable becomes unused dead code. Consider adding a brief comment noting the conditional dependency, e.g.:

Suggested change
var ftkGitTag = loadTextContent('../../fx/ftktag.txt') // cSpell:ignore ftktag
var ftkGitTag = loadTextContent('../../fx/ftktag.txt') // cSpell:ignore ftktag // Only used by ftkReleaseFile dataset when !useLocalOpenData

@flanakin flanakin added this to the v14 milestone Mar 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs: Attention 👋 Issue or PR needs to be reviewed by the author or it will be closed due to no activity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants