Skip to content

Exact permissions granted

This page is exhaustive by design: everything sprig’s installer touches, so your security review has one canonical source. The installer also has a preview mode (--what-if) that prints its plan without changing anything.

Run-time identities: control plane, gateway, and serving

Section titled “Run-time identities: control plane, gateway, and serving”

Three user-assigned managed identities keep the runtimes apart. The platform API attaches only the control-plane identity, and the gateway attaches only the gateway identity. The shared data service attaches the serving identity, and so does the Fabric schema reader (ca-<prefix>-fabric-connector) that an install adds when Fabric sources are enabled. No runtime attaches two identities.

Azure attaches roles to identities rather than to workloads, so any identity shared by two containers grants each of them the union of both sets. That is why the gateway has its own: the key that unwraps its sign-in cookie ring must not be reachable from the shared data service, which has no use for it.

That principle cuts the other way for the one identity that is shared, so it is worth stating plainly. The Fabric schema reader runs as id-<prefix>-serving, so it holds every grant in the serving rows below, including the versioned-configuration blob read and the on-behalf-of client secret. It uses neither. Two things bound that: both grants are read-only and scoped to a single container and a single named secret, and enabling Fabric adds no new role assignment anywhere, so the serving identity’s role set is identical whether or not Fabric is enabled. If you would rather no Fabric workload be able to reach those two, leave Fabric sources unconfigured and the container is never deployed.

The serving identity keeps its name deliberately. If you have run CREATE USER [id-<prefix>-serving] FROM EXTERNAL PROVIDER against a source database, that grant is unaffected by this split and needs no change. A Fabric Warehouse or lakehouse source is granted the same way, to the same identity. That database-side grant is the whole of sprig’s access to Fabric data: no Azure role assignment in your subscription grants any access to it, and you can revoke it at the source without touching the installation.

Identity Grant Scope Purpose
Control plane Storage Table Data Contributor The platform storage account Write metadata and audit events
Control plane Storage Blob Delegator The platform storage account Create a short-lived user-delegation key for the exact staging-archive upload grant; this role does not grant blob data access by itself
Control plane Storage Blob Data Owner Only the existing bundles container Verify and extract archives, tag generated files for lifecycle safety (blobs/tags data actions exist in no lesser built-in role), and delete abandoned publish data; it cannot write another container
Control plane Storage Blob Data Contributor Only the existing dab-config container Publish immutable versioned data-service configuration and read it back for version discovery; no tag actions needed here
Control plane Storage Blob Delegator The source-retention storage account Mint short-lived, read-only user-delegation grants for owner source read-back
Control plane <prefix>-source-writer-<subscription-hash> (Sprig custom role) The source-retention storage account Create per-app containers and write, read, and tag source archives. The stable subscription suffix prevents tenant-wide name collisions. The role carries no blobs/delete data action, so application code structurally cannot destroy retained source
Control plane <prefix> DAB Revision Restarter (Sprig custom role) Only the shared data service Read and restart the existing data-service revision after selecting an immutable configuration bundle; cannot change its image, identity, environment, secrets, or traffic
Control plane SQL DB Contributor The platform-owned Azure SQL logical server Create/manage per-app databases; no server-level or security-admin rights
Control plane Application.ReadWrite.OwnedBy (Graph app role) Tenant, restricted to applications the identity itself created Historically per-app Entra registrations; superseded by per-app Entra groups (below), kept for compatibility
Gateway Serving.Read (platform API app role) The sprig-platform-api enterprise application Read the small serving descriptor the gateway resolves each app from; application-only and no client secret
Gateway Storage Table Data Contributor Only the existing DataAudit table Append the gateway’s signed-in data-access audit events without write access to app metadata or active-version pointers
Gateway Storage Blob Data Reader The platform storage account Read published app bundles; the admin console is inside the signed gateway image
Gateway Storage Blob Data Contributor Only the existing dataprotection container Read and write the key ring that encrypts the sign-in cookie. The ring is rewritten as keys roll, so read alone will not do. The ring is stored wrapped, so this grant alone yields ciphertext
Gateway Key Vault Crypto User Only the single key sprig-gateway-dataprotection Wrap and unwrap that key ring. Wrap/unwrap only: it cannot create, rotate, delete, or read the key material, and it cannot reach any other key in the vault
Serving Storage Blob Data Reader The platform storage account Read versioned data-service configuration; cannot write blobs. This is the shared data service’s only storage grant and it holds no write grant anywhere
All three identities Container Registry Repository Reader The dedicated release ACR, with an ABAC condition restricted to repository names beginning sprig/ Pull only sprig/* release images; cannot list the registry catalog. This is the one serving-identity grant the Fabric schema reader does use, to pull its own image
Control plane Key Vault Secrets User Only the <prefix>-platform-api-client-secret secret Resolve the platform API’s OBO client credential for source schema discovery; cannot read the serving secret
Control plane, when certificate binding is enabled Key Vault Secrets User Only the configured wildcard certificate secret Let Container Apps import the certificate without granting access to other secrets
Serving Key Vault Secrets User Only the <prefix>-obo-client-secret secret in that vault Resolve DAB’s on-behalf-of client credential; cannot read the platform API secret or the wildcard certificate

Standing access differs by source kind, so the inventory has to say which is which rather than give one answer.

Source kind Who the database authenticates for a viewer’s query Who reads its schema at registration Standing sprig access to the data
azure-sql (db-delegated, the default) The signed-in viewer, by on-behalf-of token exchange The signed-in Ops user, by the same exchange None. sprig holds no credential that reads this source by itself
fabric-dw (gateway-enforced, the only mode this kind supports) The id-<prefix>-serving identity, with sprig filtering per viewer above the database The id-<prefix>-serving identity, not the Ops user Yes, and it is the point: whatever you granted that identity at the source, for as long as you grant it
fabric-semantic (db-delegated, the only mode this kind supports) The signed-in viewer, always - a service identity would bypass the model’s row-level security, so none exists for this kind The signed-in Ops user, over Power BI on-behalf-of; the model’s own permissions decide what the catalog shows None. sprig holds no credential that reads a semantic model by itself

The fabric-dw row is the recorded exception, not a hidden one. Every registration in gateway-enforced mode is written to the audit log, the console shows the mode on the source, and approving a share for an app backed by such a source is therefore also a data-access decision. See Data access for what that means for viewers and approvers.

Source registration and lifecycle operations store server and database metadata only. The source-management API receives no Key Vault role. For an installer-created Acmebot vault, the signed-in installer receives vault-scoped Key Vault Secrets Officer so it can create and rotate the OBO credentials, and vault-scoped Key Vault Crypto Officer so it can create the key that wraps the gateway’s cookie key ring. Both are held by the person or service principal running the install, never by a runtime identity: the gateway gets wrap/unwrap on one key and no key management at all. On a bring-your-own vault, the operator supplies equivalent access. Runtime role assignments have no separate charge and reuse the existing vault.

When Acmebot is deployed, its own managed identity receives DNS Zone Contributor on only the apps.<domain> Azure DNS zone so it can create DNS-01 challenge records.

No subscription-scope RBAC. No Application.ReadWrite.All. No directory read of other applications. No Contributor on builder or app resources: publishing an app is a database write (a Blob version + a pointer flip), not an Azure resource operation.

Archive publishing reuses the existing storage account and bundles container. The separate gateway and serving identities are required credential-isolation boundaries; managed identities and Azure RBAC assignments have no separate fixed charge. The dataprotection container reuses the existing storage account and holds a handful of small key-ring blobs, billed as ordinary capacity and Blob operations. The wrapping key is one RSA key in the vault already provisioned, billed per key operation, and it is used only when a gateway replica starts or the ring rolls, so at pilot scale both are a rounding error. Publishing continues to incur only the storage capacity and Blob operation charges described under Costs.

Object Kind Notes
sprig-platform-api App registration (confidential client) Token audience for the control-plane/publish API; exposes one delegated scope (access_as_user), the user-only Ops role, and the application-only Serving.Read role assigned to the serving managed identity. Holds a delegated Azure SQL user_impersonation permission - plus Power BI Dataset.Read.All only when the Fabric inputs were supplied at install time (declared and admin-consented then; removed and revoked on a reinstall without them) - and its own client secret (Key Vault only) so it can read a source’s schema as the signed-in Ops user during register_source (on-behalf-of - the SQL hop for SQL-shaped kinds, the Power BI hop for semantic models)
sprig-gateway App registration The audience for every builder/viewer token; Application ID URI is the gateway’s MCP URL; defines the builder/viewer app roles
sprig-connector App registration (confidential client) Pasted into the Claude org admin console; its only delegated permission is the gateway’s own scope
sprig-cli App registration (public client) Claude Code’s native OAuth client (loopback redirect); pre-authorized for the gateway scope so builders see no extra consent prompt
sprig-obo App registration (confidential client) DAB’s on-behalf-of token exchange toward Azure SQL; its secret lives in Key Vault only
sprig-operators (security group) Entra group Receives the platform API’s Ops role; direct membership controls who can operate the platform
sprig-users (security group) Entra group Holds the gateway’s builder/viewer app roles; membership is how you decide who can use sprig at all
Per published app: two Entra groups app-<name>-viewers, app-<name>-builders Checked by the gateway on every request. No per-app Entra app registration: that’s the pre-gateway shape (below)

These permissions act only on behalf of the signed-in person. They do not give an application unattended access as itself.

Client Delegated permission Purpose
sprig-gateway Microsoft Graph User.Read Read the signed-in person’s basic profile and check that person’s per-app group memberships
sprig-gateway Azure SQL Database user_impersonation Exchange the person’s token to query an authorized data source as that person
sprig-gateway sprig-platform-api access_as_user Call the platform control API as the signed-in person
sprig-platform-api Azure SQL Database user_impersonation Inspect source schema as the signed-in Ops user through the second OBO hop; tenant-wide admin consent is required
sprig-platform-api (only when Fabric inputs are supplied at install time) Power BI Service Dataset.Read.All (delegated) Read a semantic model’s catalog as the signed-in Ops user; tenant-wide admin consent is granted at install and revoked on a reinstall without the Fabric inputs. Delegated-only: no user, no token
sprig-obo Azure SQL Database user_impersonation Complete the shared data layer’s on-behalf-of exchange to Azure SQL as the signed-in person
sprig-connector and sprig-cli sprig-gateway gateway scope Call the MCP gateway as the signed-in person; both clients are pre-authorized for this scope

The installer grants the gateway-to-platform API consent required by the admin host. It also attempts tenant-wide admin consent for the gateway’s declared Graph and Azure SQL permissions. If the installing identity cannot grant that consent, the installer prints the exact command for a Global Administrator or Privileged Role Administrator to run.

Resource Where Purpose
Resource group rg-sprig-platform Subscription Platform footprint
VNet vnet-<prefix>-platform and dedicated Container Apps subnet Platform RG Foundation network boundary for the shared runtime and future source-VNet peering
Storage account (+ tables, + a bundles Blob container) Platform RG Metadata, audit, versioned app bundles
Source-retention storage account (one Blob container per app) Platform RG Published source archives, kept apart from the platform account so source-writing rights reach nothing else
Managed application runtime Platform RG Runs the signed release, including the Entra-protected operator endpoint and published app access
Dedicated Azure Container Registry (Basic) Platform RG Stores signed release images copied into the subscription; its public endpoint accepts authenticated imports, while admin and anonymous access stay disabled
Azure SQL logical server (platform-owned) Platform RG Hosts per-app serverless databases; the platform identity is its Entra admin
Azure SQL database sprig-platform (Basic) Shared logical server Stores platform metadata; startup migrations complete before the platform becomes ready
Key Vault Platform RG (Acmebot-created by default, or your own with -k) The OBO client secrets (sprig-obo for DAB, sprig-platform-api for schema discovery) and the *.apps.<domain> wildcard certificate
Azure DNS zone apps.<domain> (only with -d) Platform RG One delegated zone; every app is a subdomain of it
Three user-assigned managed identities Platform RG Separate control-plane writer, gateway, and bundle-read-only serving identities
Fabric schema reader (only when Fabric sources are enabled) Platform RG Reads Fabric source schemas during discovery; never reachable from the internet. Not created at all unless you supply the Fabric installer inputs
App Insights + Log Analytics Platform RG Monitoring
Subscription budget Subscription Spend alerts

onboard_builder and sprig builders onboard <upn> all add the person to the sprig-users group. They create no per-builder resource group, Azure role assignment, or sandbox. The group is the authorization boundary. See Onboarding builders.

What the person running the installer needs

Section titled “What the person running the installer needs”

Once, at install time: Owner on the target subscription and Entra rights to create app registrations and grant admin consent. The installer runs under that person’s az login; it stores no credentials.

The Azure CLI session must be an interactive user. For release import verification and image cleanup, the installer creates or reclaims one temporary Container Registry Repository Contributor assignment at the dedicated registry, conditioned to repository names beginning sprig/. It uses that assignment only for repository metadata and cleanup, audits the effective boundary, and revokes the Sprig-created assignment on every exit. A separately pre-existing exact conditional assignment is never deleted. No catalog-listing role or registry credential is granted.

  • No secrets on builder machines. Builders authenticate through the Claude connector (org-managed OAuth) or Claude Code’s native OAuth. Organization skill archives contain only workflow instructions and helper files: no npm bootstrap, credentials, or device-code authentication.
  • No platform-held credential to an azure-sql source. Every read of one runs through the gateway’s data proxy as the real, signed-in caller (on-behalf-of); the platform’s own managed identity never queries that data directly. This does not extend to fabric-dw, which is gateway-enforced and is read by the serving identity; see Whose identity reads your data above.
  • No outbound calls from the platform to any vendor endpoint. sprig has no telemetry service.
  • No source-registry credential in the running platform. Temporary credentials are used by the operator only while importing a release into the dedicated release registry.
  • No credential for the dedicated release registry. Each runtime authenticates with its attached managed identity, which can pull only sprig/* and cannot list the registry catalog.