Terraform Provider for Microsoft Fabric: #1 Accelerating first steps using the CLIs
Terraform is the dominant infrastructure as code tool used for declarative cloud deployments. In the first post of this series we’ll explore how to get up and running automating Fabric Administration tasks using both the Fabric CLI and the Terraform Provider for Microsoft Fabric to set up an initial config ready for development.
This short blog series will provide practical guidance to get you automating quickly. This post is the first in the series.
- Accelerating first steps using the CLIs.
- Using MCP servers and Fabric CLI to help define your fabric resources.
- Creating a workload identity with Fabric permissions.
- Deploying a fabric config with Terraform in GitHub Actions.
If you refer to the Hashicorp Terraform Provider for Fabric documentation then you’ll find a guide for manually configuring authentication for the user context. You can accelerate this manual process with the CLI commands on this page and quickly get a simple Terraform example working with a Fabric Capacity as a jumping off point for developing your own config.
Later posts in the series will help you develop that config before configuring a workload identity and deploying with GitHub Actions.
It is assumed that you have Visual Studio Code with the Hashicorp Terraform extension, GitHub Copilot, and a Bash environment (e.g. WSL on Windows, or macOS) with Terraform, Azure CLI, GitHub CLI and jq installed. It is also assumed that you already have some experience with Terraform.
What is the user context and the app registration for the user context?
Initial development for a Terraform config is run from a local session using the developer’s permissions, with test variable values used to deploy to a dev subscription. This user context allows a faster inner loop style of testing before you get to the point where you have a working config and look to move to an initial production deployment.
When using the azurerm and azapi providers then Terraform’s authentication defaults to using your cached Azure CLI token for the management control plan. When using the Fabric provider, it works a little differently as you first need to create and configure an app registration for the Fabric APIs instead.
You can then login against the app reg endpoint and that caches the token that is used for the fabric provider user context.
User context app registration process
Run the commands to accelerate this one-off task, mirroring the manual steps found in the Creating an App Registration for the user context guide.
- Create an app registration.
- Add a set of scoped permissions for the Fabric and Graph APIs.
- Expose an API endpoint.
- Pre-authorize the Azure CLI, PowerShell, and Power BI applications.
name=fabric_terraform_provider
uri="api://$(az account show --query tenantId -otsv)/$name"
az ad app create --display-name $name --identifier-uris $uri
az ad app update --id $uri --required-resource-accesses '[{"resourceAppId":"00000003-0000-0000-c000-000000000000","resourceAccess":[{"id":"e1fe6dd8-ba31-4d61-89e7-88639da4683d","type":"Scope"},{"id":"b340eb25-3456-403f-be2f-af7a0d370277","type":"Scope"}]},{"resourceAppId":"00000009-0000-0000-c000-000000000000","resourceAccess":[{"id":"4eabc3d1-b762-40ff-9da5-0e18fdf11230","type":"Scope"},{"id":"b2f1b2fa-f35c-407c-979c-a858a808ba85","type":"Scope"},{"id":"445002fb-a6f2-4dc1-a81e-4254a111cd29","type":"Scope"},{"id":"8b01a991-5a5a-47f8-91a2-84d6bfd72c02","type":"Scope"}]}]'
az ad app update --id $uri --set api='{"acceptMappedClaims":null,"knownClientApplications":[],"oauth2PermissionScopes":[{"adminConsentDescription":"Allows connection to backend services for Microsoft Fabric Terraform Provider","adminConsentDisplayName":"Microsoft Fabric Terraform Provider","id":"1ca1271c-e2c0-437c-af9a-3a92e745a24d","isEnabled":true,"type":"User","userConsentDescription":"Allows connection to backend services for Microsoft Fabric Terraform Provider","userConsentDisplayName":"Microsoft Fabric Terraform Provider","value":"access"}],"preAuthorizedApplications":[],"requestedAccessTokenVersion":null}'
az ad app update --id $uri --set api='{"acceptMappedClaims":null,"knownClientApplications":[],"oauth2PermissionScopes":[{"adminConsentDescription":"Allows connection to backend services for Microsoft Fabric Terraform Provider","adminConsentDisplayName":"Microsoft Fabric Terraform Provider","id":"1ca1271c-e2c0-437c-af9a-3a92e745a24d","isEnabled":true,"type":"User","userConsentDescription":"Allows connection to backend services for Microsoft Fabric Terraform Provider","userConsentDisplayName":"Microsoft Fabric Terraform Provider","value":"access"}],"preAuthorizedApplications":[{"appId":"871c010f-5e61-4fb1-83ac-98610a7e9110","delegatedPermissionIds":["1ca1271c-e2c0-437c-af9a-3a92e745a24d"]},{"appId":"00000009-0000-0000-c000-000000000000","delegatedPermissionIds":["1ca1271c-e2c0-437c-af9a-3a92e745a24d"]},{"appId":"1950a258-227b-4e31-a9cf-717495945fc2","delegatedPermissionIds":["1ca1271c-e2c0-437c-af9a-3a92e745a24d"]},{"appId":"04b07795-8ddb-461a-bbee-02f9e1bf7b46","delegatedPermissionIds":["1ca1271c-e2c0-437c-af9a-3a92e745a24d"]}],"requestedAccessTokenVersion":null}'
az ad app owner add --id $uri --owner-object-id $(az ad signed-in-user show --query id -otsv)
az ad app show --id $uri --output jsonc
echo "App Registration created. Authenticate with:"
echo "az login --scope $uri/.default"
Find the app registration in the Entra Admin Portal.



The app reg is now in place and may be used by all users within your tenant. You’ll authenticate against the endpoint soon, but first let’s make sure you have a Fabric Capacity to use and then create your initial Terraform config.
Fabric Capacity
As well as the app registration, you will need a Fabric Capacity as the starting point for your config, there are three types:
- Fabric Capacity (F-SKU, may be created by azurerm_fabric_capacity).
- Trial Capacity (T-SKU).
- Premium Per User Capacity (P-SKU, due to be retired).
Use the Fabric CLI command to list your capacities and find the capacity name or ID that is required by the fabric_capacity data source in the starter config above.
fab ls -l .capacities
This is one of the quickest ways to check which capacities you have access to. Find the correct capacity in the list, and trim the .Capacity suffix from the first column to get the capacity name, or use the capacity ID from the second column.
name id sku region state --------------------------------------------------------------------------------------------------------------------------- Premium Per User - Reserved.Capacity 59d17bf8-cda2-4c43-824a-ec3a8078908d PP3 West US 3 Active Trial-20250314T172025Z-xmVeQXcryUKTbE5vcFY5Dg.Capacity 29dc2bec-dc5e-4c0a-85bc-564d96106653 FT1 West US 3 Active example.Capacity 3da9391c-0cbb-4005-952a-1007a3021888 F2 UK South Active
Remember that F-SKUs will only be visible to you if you:
- Are a capacity administrator (requires user principal names for users or object IDs for workload identities).
- Have contributor in the Fabric Admin Portal (navigate to Capacity settings > Fabric Capacity tab > click on the capacity name > update Contributor permissions section).
- Have the Fabric Administrator Entra RBAC role.
Starter config
Here is an example starter config specifying a data source for a Fabric capacity called ‘example’. You may create it as a single main.tf file, but feel free to split it out into multiple files as per your preferences.
terraform {
required_version = ">= 1.8, < 2.0"
required_providers {
fabric = {
source = "microsoft/fabric"
version = "~> 1.0"
}
}
}
provider "fabric" {
# tenant_id = <guid> # ARM_TENANT_ID
# use_oidc = true # ARM_USE_OIDC
# use_azuread_auth = true # ARM_USE_AZUREAD
# client_id = <guid> # ARM_CLIENT_ID
preview = false
}
variable "fabric_capacity_name" {
description = "The name of the fabric capacity."
type = string
default = "example"
}
data "fabric_capacity" "example" {
display_name = var.fabric_capacity_name
lifecycle {
postcondition {
condition = self.state == "Active"
error_message = "Fabric Capacity is not in Active state. Please check the Fabric Capacity status."
}
}
}
output "fabric_capacity_id" {
description = "The ID of the fabric capacity."
value = data.fabric_capacity.example.id
}
The config above is a good jumping off point before you start defining workspaces, RBAC role assignments and more.
Authenticate
Authenticate against the app registration’s endpoint to cache the token for the app reg scope.
az login --scope api://$(az account show --query tenantId -otsv)/fabric_terraform_provider/.default
If you do not have access to an Azure subscription then add the --allow-no-subscriptions and —tenant switches.
You are now authenticated to the user context and ready to run the familiar Terraform workflow.
Terraform workflow
Initialise Terraform.
terraform init
Terraform will download the Fabric provider and you will get the message that it has been successfully initialized.
Initializing the backend… Initializing provider plugins… – Finding microsoft/fabric versions matching ‘~> 1.0’… – Installing microsoft/fabric v1.3.0… – Installed microsoft/fabric v1.3.0 (self-signed, key ID 90F5BC3EE275B15A) Partner and community providers are signed by their developers.
If you’d like to know more about provider signing, refer to the documentation Plugin signatures.
Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run ‘terraform init’ in the future.
Terraform has been successfully initialized! You may now begin working with Terraform. Try running ‘terraform plan’ to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
You would normally use terraform fmt, terraform validate, and terraform plan to check your config, but as the starter example is configured correctly and is mostly harmless then you can jump straight to applying the config. The command below allows you to override the default for the fabric_capacity_name variable.
terraform apply --var fabric_capacity_name="example"
If you have successfully authenticated against the fabric APIs with the app registration then you should see a prompt to perform the actions and the fabric_capacity_id will be output.
data.fabric_capacity.example: Reading... data.fabric_capacity.example:
Read complete after 5s [id=3cab994c-b48d-49d6-a821-8ff055ad1c61] Changes to Outputs: + fabric_capacity_id = "3cab994c-b48d-49d6-a821-8ff055ad1c61"
You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure. Do you want to perform these actions? Terraform will perform the actions described above. Only ‘yes’ will be accepted to approve. Enter a value: yes, apply complete!
Resources: 0 added, 0 changed, 0 destroyed. Outputs: fabric_capacity_id = "3cab994c-b48d-49d6-a821-8ff055ad1c61"
Success! You are ready to return to the fabric provider documentation at Terraform and begin to expand your config.
Summary
Microsoft Fabric brings all of your most important data to one place for analytics and to fuel your Agentic AI. The Fabric CLI and Terraform Provider for Microsoft Fabric offer a wealth of new options for automation and now administrators familiar with Terraform can declaratively automate fabric administration tasks.
In the next blog in the series we will look at practical examples on how you can use both the Terraform MCP Server and the Fabric CLI to help you define the more complex Microsoft Fabric resources in Terraform.