Platform Configuration¶
This page is for the platform team. It describes how the solution is laid out as code, which prerequisites must be in place, and how the tiers are configured. For the design see Architecture.
Reference design, your deployment may differ
Variable names and defaults below are those of the solution code. The pipelines and the tfvars files of a deployment
live in a configuration repository of that deployment, which is not part of the solution source.
Repository layout¶
The solution is delivered as a Terraform code repository. A deployment adds its own configuration (the tfvars files) and
pipelines.
| Path | Purpose |
|---|---|
infra/deploy/shared |
Root module of the shared tier: capacities, custom role, auto-pause |
infra/deploy/workload |
Root module of the workload tier: gateway, workspaces, connections, data lake |
infra/deploy/governance |
Root module of the optional Purview tier |
infra/deploy/observability |
Root module of the optional Grafana tier |
infra/modules/fabric-workspace |
Workspace, role assignments, private link, network policy scripts, Git, Lakehouses, Warehouses |
infra/modules/fabric-connections |
ADLS, SQL, Oracle Cloud Storage connections, managed private endpoints, outbound connection rules |
infra/modules/purview, infra/modules/grafana |
Modules of the optional tiers |
docs/ |
HLD, ADR and runbooks of the solution |
Tooling. Terraform >= 1.13, < 2.0. Providers: azurerm (>= 4.0.0, < 5.0), azuread, azapi and the Microsoft fabric
provider (>= 1.7.0, < 2.0, in preview mode) for the workload tier, and grafana (>= 3.0.0, < 4.0) for the observability
tier. The state is stored in an Azure storage account (azurerm backend) with Entra ID authentication. Several steps call
Fabric REST APIs through PowerShell scripts, so the agent that runs the pipeline needs PowerShell (pwsh) and the
Azure CLI with a signed-in session.
Prerequisites¶
Some steps cannot be automated and must be done before the first deployment.
| Prerequisite | Detail |
|---|---|
| A spoke per environment and one shared spoke | The spoke canvas provides the VNet, private endpoint subnet, Key Vault, storage account and Log Analytics (Spoke canvas). The workload tier also needs a subnet for the VNet data gateway. |
| Graph permissions for the service principal of the shared spoke | Application.Read.All, Directory.Read.All and User.Read.All. Needed to set the capacity administrators. |
| Fabric admin portal: workspace-level networking | Enabled in the tenant settings |
| Fabric admin portal: service principal access | Enabled, so that the deployment identity can use the Fabric APIs |
| Fabric admin portal: guest account access | Enabled |
| Fabric admin portal: GitHub access | Enabled, for workspaces with a Git link |
| Fabric admin portal: Configure workspace-level outbound network rules | Enabled, so that workspace admins can use outbound protection |
| Secrets in the spoke Key Vault | The client ID and secret of the service principal for each ADLS or SQL connection, username and password for basic connections and Oracle Cloud Storage, and for Git a personal access token in a secret named GitHub-PAT |
| Entra ID groups | One per workspace role you want to use, and the Grafana groups when the observability tier is used |
The source lists the four Fabric tenant settings as screenshots. Confirm the exact setting names in the Fabric admin portal of your tenant.
The deployment identity also needs rights on the spoke: it creates a key and reads secrets in the spoke Key Vault, assigns roles on the storage account, and creates resources in the subscription. What the spoke service principal has is described in Spoke canvas.
Variables common to all tiers¶
| Variable | Notes |
|---|---|
location |
westeurope, northeurope, swedencentral or uksouth |
environment |
development, test, acceptance, production (and shared for the shared and governance tiers) |
workload_name |
At most 8 characters |
spoke_config |
Names of the spoke resources to build on (see below) |
spoke_config for the shared tier: subscription_id, resource_group_name, log_analytics_name, key_vault_name,
storage_account_name, vnet_name, snet_pe_name. The workload tier adds snet_gateway_name. The governance tier takes a
smaller set. These are the names of resources that the spoke canvas creates (What you get). The solution reads them with data sources and does not create them.
Shared tier¶
capacity_administrators = ["<spoke service principal object id>"]
fabric_capacities = {
development = { sku = "F4" }
production = { sku = "F8" }
}
capacity_auto_pause = { enabled = false } # see Capacity auto-pause
capacity_operator_group_ids = []
| Variable | Purpose |
|---|---|
capacity_administrators |
Principal IDs that become capacity administrators: the spoke principals of the workloads that use the capacity, and optionally users |
fabric_capacities |
Map of capacities. The key becomes part of the capacity name and is what the workload tier refers to. At least one capacity. SKU F2, F4, F8, F16, F32, F64, F128, F256, F512, F1024 or F2048. |
capacity_auto_pause |
See Capacity auto-pause |
capacity_operator_group_ids |
Groups that get the Fabric Capacity Operator role |
The resource providers Microsoft.Fabric and Microsoft.Logic are registered by the deployment.
Workload tier¶
fabric_capacities = {
development = { display_name = "<name of the capacity from the shared tier>" }
}
workspaces = {
engineering = {
capacity_key = "development"
admins_group_id = "<entra group object id>"
contributors_group_name = "<entra group display name>"
viewers_group_id = "<entra group object id>"
outbound_network_policy_enabled = true # outbound protection off, see Workspace network policy
git_config = {
owner_name = "<organisation>"
repository_name = "<repository>"
branch_name = "<branch>"
directory_name = "<directory>" # must exist in the repository
}
lakehouses = {
bronze = { description = "Raw data", enable_schemas = true }
}
warehouses = {
silver = { description = "Business entities", collation_type = "Latin1_General_100_BIN2_UTF8" }
}
adls_connections = {
landing = {
container_name = "landing"
client_id_secret_name = "<secret name>"
client_secret_secret_name = "<secret name>"
}
}
workspace_connections = {
to-reporting = { workspace_key = "reporting" }
}
managed_private_endpoints = {
sql = {
target_private_link_resource_id = "<resource id>"
subresource_type = "<sub-resource>"
}
}
}
}
| Setting of a workspace | Notes |
|---|---|
capacity_key |
Must be a key of fabric_capacities (validated) |
admins_*, contributors_*, members_*, viewers_* |
Each role has _group_id and _group_name. The ID wins. |
outbound_network_policy_enabled |
Default false (outbound deny). See Workspace network policy. |
git_config |
github_url defaults to github.com. See Connectivity. |
lakehouses |
description, enable_schemas |
warehouses |
description, collation_type (two allowed values) |
adls_connections |
Container and the two secret names. A container is created per connection. |
sql_connections |
Server, database, client ID and secret names (service principal) |
sql_connections_basic |
Server, database, username and password secret names |
oracle_cloud_storage_connections |
API endpoint, username and password secret names |
workspace_connections |
Target workspace key (a workspace of the same deployment) |
managed_private_endpoints |
Resource ID of the target and the sub-resource type |
data_pipelines |
Accepted by the variable, but not passed on by the root module |
Validations in the code: every capacity_key must exist, Warehouse and Lakehouse names must be unique within a workspace and
across both types, and collations must be one of the two allowed values. A Fabric capacity must be found by display_name
(a data lookup), so the shared tier must be deployed first.
What the workload tier creates per run is listed on Architecture. Notable behaviour:
- One VNet data gateway is created for each capacity key of the deployment (1 member gateway, 30 minutes of inactivity before sleep), in the gateway subnet of the spoke. All workspaces of a capacity use it.
- The storage account key
expiration_dateis ignored after creation, and the private DNS zone groups of private endpoints are ignored because policy sets them. - The network policy and Git steps run PowerShell scripts as
local-execprovisioners, triggered by changes of their inputs.
Deploying a change¶
Changes follow Request and change. In short: edit the configuration, open a pull request, review the plan, deploy through the pipeline. Check the plan for:
- additive changes only when adding a role group, connection or Lakehouse,
- no replacement of a workspace resource,
- the
403skips of the network scripts on small SKUs (Workspace network policy).