Configuration
Everything is an environment variable (FABRIC_*); flags override env; then
validation derives dependent values. There is no config file.
The one required setting
Section titled “The one required setting”| Env | Flag | Meaning |
|---|---|---|
FABRIC_ENTRA_ISSUER | -entra-issuer | The exact iss bearer tokens must carry — an entra-emulator issuer (https://entra-emulator:8443/{tenant}/v2.0) or a real Entra tenant (https://login.microsoftonline.com/{tenant}/v2.0). Startup fails without it. |
Everything else
Section titled “Everything else”| Env | Flag | Default | Meaning |
|---|---|---|---|
FABRIC_ADDR | -addr | :9443 | Listen address. |
FABRIC_DATA_DIR | -data-dir | ./data | SQLite + TLS state directory, so workspaces, items and OneLake contents survive a restart. Set it to the empty string for a fully in-memory run (fresh DB and ephemeral cert — ideal for tests): unset and set-empty differ deliberately, and the compose files use the empty form so a throwaway stack leaves nothing behind. The Docker image sets /data. |
FABRIC_ENTRA_JWKS_URL | -entra-jwks-url | derived | Where signing keys are fetched. Derived from the issuer by the Entra convention: {origin}/{tenant}/v2.0 → {origin}/{tenant}/discovery/v2.0/keys. Set explicitly only when the JWKS lives elsewhere (e.g. reachable under a different host than the advertised issuer). |
FABRIC_ENTRA_TLS_INSECURE | -entra-tls-insecure | false | Skip TLS verification when fetching the JWKS — needed when entra-emulator serves its self-signed cert (the compose file sets it). Never needed against real Entra. |
FABRIC_AKV_VAULT_HOST | — | (none) | One extra host:port a vault secret reference may resolve against, besides Azure’s own *.vault.azure.net and the sovereign equivalents. The compose file sets keyvault-emulator:8444. This is a security boundary: resolving a reference sends a vault-audience bearer token to the host the connection names, so anything unlisted is refused — otherwise a hostile vaultURI exfiltrates the token, and (pointed at a real tenant) a real Azure one. Azure constrains the URI the same way. |
FABRIC_ARM_URL | -arm-url | (none for the binary; this repo’s compose sets it) | arm-emulator origin. Microsoft.Fabric/capacities created over ARM appear on GET /v1/capacities. The binary still defaults to empty, so a bare fabric-emulator is standalone; the compose runs arm-emulator and points at it, because capacities ARE ARM resources and a stack without one is a visibly smaller Fabric. Set FABRIC_ARM_URL= explicitly empty to opt back out to the seeded local capacity — standalone fabric-cicd works either way. |
FABRIC_ARM_POLL_SECONDS | -arm-poll-seconds | 5 | How often the ARM capacities feed is refreshed. 0 uses the 5s default. A transient ARM outage leaves last-known capacities in place. |
FABRIC_DISABLE_TLS | -disable-tls | false | Serve plain HTTP instead of self-signed TLS. Handy for curl exploration or behind a TLS-terminating proxy. |
| — | -lro-delay | 0 | Virtual seconds an async operation stays Running before succeeding. 0 = completes on the next poll. Combine with clock control for deterministic polling tests. |
Booleans accept 1, true, yes, on (case-insensitive); anything else is
false. Retry-After on 202 responses is fixed at 1 second.
Real-compute sidecars
Section titled “Real-compute sidecars”Empty by default for the bare binary — leave them unset and unattached surfaces answer with an honest 501, not a fake result. Point them at running sidecars to route to real compute; see real compute and warehouse TDS for the full setup.
docker compose up sets FABRIC_SPARK_AGENT_URL/FABRIC_SQL_TDS_ADDR/
FABRIC_WAREHOUSE_SQL_URL for you by default (via the auto-loaded
docker-compose.override.yml, which also brings up the sidecars they point
at) — the binary’s own empty defaults below only apply if you run it directly,
or opt out with docker compose -f docker-compose.yml up.
| Env | Flag | Default | Meaning |
|---|---|---|---|
FABRIC_SPARK_LIVY_URL | -spark-livy-url | (empty) | Livy endpoint for real Spark session/statement execution. |
FABRIC_SPARK_AGENT_URL | -spark-agent-url | (empty) | Spark agent endpoint fronting the Livy cluster. |
FABRIC_SQL_TDS_ADDR | -sql-tds-addr | (empty) | TDS listen address for the SQL analytics endpoint. |
FABRIC_WAREHOUSE_SQL_URL | -warehouse-sql-url | (empty) | Backing SQL engine URL for warehouse query execution. |
FABRIC_TENANT_ADMINS | -tenant-admins | (empty) | Comma-separated principal ids (oid, or appid for a service principal) that count as Fabric administrators for /v1/admin/*. The gate is graded as Microsoft documents it: a read needs a Fabric administrator or a service principal, a write needs a Fabric administrator with no service-principal escape. Empty means nobody is an administrator, so every admin mutation is refused — the honest default, since the alternative is the pre-gate behaviour where every authenticated caller could create governance domains. Membership is declared here, never inferred from a token claim. |
FABRIC_WEB_ACTIVITY | -web-activity | real | stub makes pipeline Web activities record success without calling anything — for a CI leg that must not reach the network. The default performs the real HTTP request, because a fabricated response is a false pass. |
FABRIC_CUSTOM_ACTIVITY | -custom-activity | real | off makes pipeline Custom (Azure Batch) activities refuse by name so no command reaches the Spark agent. The default runs the command in the agent’s container, matching a notebook cell on that same machine. The old opt-in spelling shell remains on. |
FABRIC_AIRFLOW_URL | -airflow-url | (empty) | Apache Airflow 2.10 REST API base URL. Setting it enables real ApacheAirflowJob execution. |
FABRIC_AIRFLOW_DAG_DIR | -airflow-dag-dir | (empty) | Host path shared with Airflow’s DAG folder. Required when FABRIC_AIRFLOW_URL is set. |
FABRIC_AIRFLOW_USERNAME | -airflow-username | (empty) | Optional Airflow REST basic-auth username. |
FABRIC_AIRFLOW_PASSWORD | -airflow-password | (empty) | Optional Airflow REST basic-auth password. |
FABRIC_MLFLOW_URL | -mlflow-url | (empty) | Real MLflow tracking/model-registry server base URL. Enables the workspace-scoped MLflow proxy and typed experiment/model synchronization. |
FABRIC_KAFKA_BOOTSTRAP | -kafka-bootstrap | (empty) | Apache Kafka broker host:port behind Eventstream items. Empty → item create still works (mgmt) and Spark / Custom-source execution 501s. See 51-eventstream-kafka.md. |
FABRIC_DATABRICKS_URL | -databricks-url | (empty) | databricks-emulator (or real workspace) origin. When set, DatabricksNotebook / DatabricksSparkPython submit there and dbfs: / /Workspace paths become legal. Empty keeps local Spark-agent termination and refuses those paths by name. |
FABRIC_DATABRICKS_TOKEN | -databricks-token | (empty) | PAT or OIDC access token sent to FABRIC_DATABRICKS_URL. |
FABRIC_DATABRICKS_TLS_INSECURE | -databricks-tls-insecure | false | Skip TLS verification for FABRIC_DATABRICKS_URL (databricks-emulator’s self-signed cert). |
FABRIC_DAX_URL | — | (empty) | HTTP origin of a DAX pump in front of msmdsrv (POST /v1/deploy then POST /v1/dax). Empty keeps the in-process bounded evaluator — and is what GitHub-hosted ubuntu/mac CI tests. Set-but-unreachable is a 502, not a fallback. Not a compose default, and not a macos-latest / ubuntu-latest sidecar — 52-msmdsrv-hosts.md. |
Subcommands
Section titled “Subcommands”| Command | Does |
|---|---|
fabric-emulator version | prints the release version (dev for source builds) |
fabric-emulator healthcheck | probes /health on the local instance (honors FABRIC_ADDR), exit 0 when healthy — this is the Docker image’s HEALTHCHECK, since distroless has no shell |
Issuer alignment (the one subtle bit)
Section titled “Issuer alignment (the one subtle bit)”fabric-emulator compares the token’s iss claim string-exactly against
FABRIC_ENTRA_ISSUER. Tokens carry whatever issuer entra-emulator advertises
(its login origin), which is not automatically the hostname you fetch the JWKS
from. On the compose network entra is therefore told to advertise the
network-internal origin:
entra-emulator: environment: ORIGIN_MODE: compat PUBLIC_ORIGIN: "https://entra-emulator:8443"so iss = https://entra-emulator:8443/{tenant}/v2.0 = what fabric validates.
If tokens are rejected with an issuer mismatch, this alignment is almost always
the cause. See TLS & hosts for the full story.