Microsoft Fabric Updates Blog

Terraform Provider for Microsoft Fabric: #3 Creating a workload identity with Fabric permissions

After the first two blog posts you were able to get working quickly in the user context and then some real world advice in expanding your config and defining those Fabric Administrator resources. This is a common way to develop and test your initial config. In the third and fourth blog posts we will look at implementing an example production deployment pipeline, starting in this post with creating and configuring the workload identity.

This post is the third in the series.

  1. Accelerating first steps using the CLIs.
  2. Using MCP servers and Fabric CLI to help define your fabric resources.
  3. Creating a workload identity with Fabric permissions.
  4. Deploying a fabric config with Terraform in GitHub Actions.

This workload identity config will be common to all of the main CI/CD platforms used on Azure such as GitHub Actions, Azure DevOps, GitLab, BitBucket, Jenkins, CircleCI and more.

We will create a managed identity and look at how to add authorisations for Azure, for the Microsoft Graph, and of course for the Fabric APIs to enable the Fabric Terraform Provider. This then opens up a rich mix of Terraform providers, so you can include resources from the azurerm, azapi, azuread, and fabric providers in your configs. The commands here will also create a storage account for your remote backend, with blob versioning and enforced RBAC authentication mode.

The last blog page in the series will give an example of a GitHub Actions deployment pipeline with OpenID Connect configured with a federated credential on the managed identity.

Configuring a User Assigned Managed Identity for use in CI/CD pipelines

The fabric provider documentation includes a number of options for manually creating workload identities (service principals and managed identities) for use in CI/CD pipelines. Here is an example scripted configuration using a user assigned managed identity that follows many of the security recommendations.

Core Terraform bootstrap

First, create a remote state backend and a user assigned managed identity. The storage account will enforce RBAC authorization and other security recommendations, and the managed identity will have an RBAC role assignment for writing state to the backend. In an Azure Landing Zone environment this may use the management subscription in the platform landing zone.

Customise the variable values.

terraform_resource_group_name="rg-terraform"
location="uksouth"
managed_identity_name="mi-terraform"
storage_account_prefix="saterraform"
management_subscription_id="<subscription_guid>"

Run the commands to create and configure the core bootstrap resources.

az account set --subscription $management_subscription_id
az group create --name $terraform_resource_group_name --location $location
az identity create --name $managed_identity_name --resource-group $terraform_resource_group_name --location $location
managed_identity_object_id=$(az identity show --name $managed_identity_name --resource-group $terraform_resource_group_name --query principalId -otsv)
managed_identity_client_id=$(az identity show --name $managed_identity_name --resource-group $terraform_resource_group_name --query clientId -otsv)
storage_account_name="$storage_account_prefix$(az group show --name $terraform_resource_group_name --query id -otsv | sha1sum | cut -c1-8)"
az storage account create --name $storage_account_name --resource-group $terraform_resource_group_name --location $location --min-tls-version TLS1_2 --sku Standard_LRS --https-only true --default-action "Allow" --public-network-access "Enabled" --allow-shared-key-access false --allow-blob-public-access false
storage_account_id=$(az storage account show --name $storage_account_name --resource-group $terraform_resource_group_name --query id -otsv)
az storage account blob-service-properties update --account-name $storage_account_name --enable-versioning --enable-delete-retention   --delete-retention-days 7
az storage container create --name prod --account-name $storage_account_name --auth-mode login
az role assignment create --role "Storage Blob Data Contributor" --assignee $managed_identity_object_id --scope "$storage_account_id/blobServices/default/containers/prod"
az storage container create --name dev --account-name $storage_account_name --auth-mode login
az role assignment create --role "Storage Blob Data Contributor" --assignee $(az ad signed-in-user show --query id -otsv) --scope "$storage_account_id/blobServices/default/containers/dev"

echo "Core bootstrap complete."

You have created the managed identity and storage account for the backend.

Configure Fabric tenant level Developer settings

The Developer settings in Fabric Admin portal’s tenant settings are the control point to enable workload identities to use the Fabric REST APIs used by the fabric Terraform provider. In this section we will create an Entra security group, add the managed identity, and then configure the Developer settings.

Run the example commands below to create the Entra ID security group and add the user assigned managed identity as a member.

fabric_group_name="Microsoft Fabric Workload Identities"
fabric_group_description="Service Principals and Managed Identities used for Fabric automation."
fabric_group_mail_nickname="FabricWorkloadIdentities"
az ad group create --display-name "$fabric_group_name" --description "$fabric_group_description" --mail-nickname "$fabric_group_mail_nickname"
az ad group member add --group "$fabric_group_name" --member-id "$managed_identity_object_id"
fabric_group_id=$(az ad group show --group "Microsoft Fabric Workload Identities" --query id -otsv)
echo "Created security group $fabric_group_name"

Specify the group in the Developer settings within Fabric Admin portal’s tenant settings. This configuration is the control point for the workload identity to be authorized to access the Fabric APIs used by the Terraform provider.

body=$(jq -nc --arg oid "$fabric_group_id" --arg name "$fabric_group_name" '{"enabled":true,"canSpecifySecurityGroups":true,"enabledSecurityGroups":[{"graphId":$oid,"name":$name}]}')
fab api --method post admin/tenantsettings/ServicePrincipalAccessGlobalAPIs/update -i "$body"
fab api --method post admin/tenantsettings/ServicePrincipalAccessPermissionAPIs/update -i "$body"
fab api --method post admin/tenantsettings/AllowServicePrincipalsCreateAndUseProfiles/update -i "$body"

The Fabric CLI commands are a useful example of using the fab api command to call the Fabric REST API directly, similar to using Azure CLI’s az rest command.

Fabric Admin Portal showing the Microsoft Fabric Workload Identities Entra security group specified in the Developer settings for service principals
Developer settings in Fabric Admin Portal

Authorise access to a Fabric Capacity

At this point the managed identity can access the Fabric REST APIs, but it does not currently have access to a Fabric Capacity F-SKU.

There are two ways to grant capacity-level access:

  1. Azure: Assign the identity as an administrator on the Azure fabric capacity resource. Requires an Azure RBAC role assignment such as Contributor role on the fabric capacity.
  2. Fabric: Assign a Fabric RBAC role (e.g. Admin, Contributor) to the capacity in the Fabric Admin Portal. Requires either the Fabric Administrator role assigned in Entra, or Admin role on the Capacity in Fabric Admin.

In this section we will add the user assigned managed identity as an Administrator on the fabric capacity in Azure. The example commands below will extend the array with the workload identity’s object ID. (It is also very simple to do this within the Azure Portal.)

Get the Fabric Capacity resource id, e.g.:

fabric_resource_id=$(az fabric capacity show --resource-group my_fabric_rg --name my_capacity_name --query id -otsv)

Then extend the array of administrators:

admins=$(az fabric capacity show --ids $fabric_resource_id --query administration.members --output json | jq --arg oid "$managed_identity_object_id" '. += [$oid]')
az fabric capacity update --ids $fabric_resource_id --administration "{\"members\": $admins}"

Additional RBAC role assignments (optional)

The managed identity can be configured with additional Azure RBAC role assignments if required. For example:

role="Contributor"
workload_subscription_id="<subscription_guid>"

Create the role assignment.

scope="/subscriptions/$workload_subscription_id"
az role assignment create --role $role --scope $scope --assignee-object-id $managed_identity_object_id --assignee-principal-type ServicePrincipal

An obvious use case here is to enable the managed identity to be able to create a Fabric Capacity using azurerm_fabric_capacity. If you are looking to adhere to least privilege recommendations, then you could first create a custom role that included "Microsoft.Fabric/*" (or a subset) in the actions array.

Additional Entra ID app role permissions (optional)

A common Fabric Administration requirement is to create a Fabric RBAC role assignment for an Entra security group to have Admin, Contributor, Member, or Viewer access to a workspace. The fabric_workspace_role_assignment requires the object ID in the principal block, so it is useful to be able to reference the azuread_group data source.

Adding app role permissions to the managed identity is a little publicized feature that opens up access to the Microsoft Graph and the azuread provider. The commands below use az rest as there is currently no support for managed identity app roles in the Azure CLI.

graph_app_id="00000003-0000-0000-c000-000000000000"
graph_object_id=$(az ad sp show --id $graph_app_id --query id -otsv)

for role in User.Read.All Group.Read.All
do
  app_role_id=$(az ad sp show --id $graph_app_id --query "appRoles[?value == '"$role"'].id" -otsv)
  body=$(jq -nc --arg graph "$graph_object_id" --arg mi "$managed_identity_object_id" --arg role "$app_role_id" '{principalId:$mi,resourceId:$graph,appRoleId:$role}')
  echo "Adding app role $role:"
  jq . <<< $body
  az rest --method post --uri "https://graph.microsoft.com/v1.0/servicePrincipals/${managed_identity_object_id}/appRoleAssignments" --body "$body"
done

You can view app roles for any managed identity in the Entra Admin portal. Select Enterprise Applications in the navigation panel and then change the Application type filter to Managed Identities and then use the search to find the managed identity. Select Permissions to view the app roles, which are the permissions in the Admin consent tab.

Entra Admin Portal screen showing the app role permissions for User.ReadBasic.All and Group.Read.All for the mi-terraform managed identity.
App role permissions for the managed identity in the Entra Admin Portal

You may add additional permissions as required, the following command lists all of the possible app roles for the Microsoft Graph:

az ad sp show --id 00000003-0000-0000-c000-000000000000 --query "appRoles[].value" -oyamlc

App role permissions for managed identities are equivalent to the API role permissions for a service principal and have implicit admin consent, so use with care.

Summary

You now have a managed identity configured with the correct permissions to write the Terraform state to the remote backend in the storage account, plus authorisations for Fabric, Azure and the Microsoft Graph.

In the final blog post in the series we will walk through adding a federated credential to enable OpenID Connect authentication from GitHub Actions, and see an example YAML workflow to deploy your synced Terraform config.

Entradas de blog relacionadas

Terraform Provider for Microsoft Fabric: #3 Creating a workload identity with Fabric permissions

octubre 22, 2025 por Santhosh Kumar Ravindran

Managed Private Endpoints support for connecting to Private Link Services is now available in Microsoft Fabric (Public REST APIs). This has been one of the top requests from our customers and the community: the ability to securely connect Fabric Spark compute to on-premises and network-isolated data sources using the option to allowlist Fully Qualified Domain … Continue reading “Securely Accessing External and On-Premises Data Sources with Fabric Data Engineering Workloads”

octubre 13, 2025 por Matthew Hicks

Microsoft OneLake is the unified data lake for your entire organization, built into Microsoft Fabric. It provides a single, open, and secure foundation for all your analytics workloads – eliminating data silos and simplifying data management across domains. The preview of Microsoft OneLake Table APIs, a new way to programmatically manage and interact with your … Continue reading “OneLake Table APIs (Preview)”