The build kit for multi-tenant .NET SaaS on Databricks.
An opinionated reference architecture and a small set of reusable components for teams that sell analytics to customers who are not themselves Databricks customers.
Project site: https://lakewright.net — the argument in one page, with the same three identities you can run locally.
Status: early, but you can run it. Implemented and tested: the tenant model, the tenant-scoped Databricks query layer, the asynchronous operation worker with crash reconciliation and resumed polling, the ASP.NET Core tier (tenant middleware, role policies, the operations API with client idempotency), the audit trail, the Declarative Automation Bundle, telemetry instruments, and the Signalboard sample — two organizations, three people, a Blazor dashboard and the same API from a terminal. Still open: cost budgets in currency, an observability export, and a reference deployment. The milestones are in ROADMAP.md, and docs/compatibility.md records exactly what has been verified against a live workspace and what has not.
Docker, and nothing else. No .NET SDK, no Databricks account, nothing to configure.
git clone https://github.com/ivanvyd/LakeWright.NET
cd LakeWright.NET/samples/Signalboard
docker compose upOpen http://localhost:8080. The landing page seeds two organizations and three people and hands you the curl commands. Sign in as someone from the other organization and the same address answers 404 rather than 403, because a 403 would confirm the work exists.
That is the isolation model in about a minute, and it runs without a workspace because tenancy and authorization never talk to Databricks. Getting started goes on to the tests, the DI wiring, and a live workspace.
Unity Catalog row filters resolve the caller with session_user(). When an ASP.NET Core backend
connects with one service principal for every tenant, that function returns the same value on every
request, so the filter predicate is identical for all of them. The result is a system that either
shows every tenant nothing or shows every tenant everything.
Databricks documents the trade-off directly, for Databricks Apps:
All actions initiated by the app use the service principal's permissions... it doesn't support user-level access control. All users who interact with the app share the same permissions defined for the service principal, which prevents the app from enforcing fine-grained policies based on individual user identity.
App identity means you filter. User identity means Unity Catalog filters. There is no third option, and there is no general on-behalf-of flow for a service hosted outside Databricks.
You find this in an audit rather than in testing, because every tenant's request returns a plausible-looking result. LakeWright.NET handles it in the query layer, along with the pieces such a product needs anyway: durable asynchronous operations, a per-tenant ceiling on Databricks compute, an audit trail, and the Databricks side deployed as code.
- Not a Databricks SDK.
Microsoft.Azure.Databricks.Clientalready covers Unity Catalog, Statement Execution and Jobs under MIT. This project depends on it. - Not a dashboard embedding library. Databricks AI/BI external embedding ships today, with row-level
security and no per-viewer fee. Use it.
LakeWright.Embeddingbrokers the token that flow needs and stops there — the tenant is signed into it rather than chosen by the caller. Rendering remains@databricks/aibi-client's job. - Not a generic ASP.NET Core SaaS starter. If you are not on Databricks, nothing here is for you.
- Not an admin portal, a workspace provisioner, or a notebook tutorial.
Databricks Apps documentation states: "You can't make Databricks apps public. Anonymous access and bypassing single sign-on (SSO) are not supported." Every end user must exist as an identity in your Databricks account, there are no custom domains, and the runtime ships Python and Node with no .NET.
Databricks Apps is the right host for internal tooling. It cannot host a customer-facing product. ADR 0001 records the evidence and settles it.
Projects appear when there is code to put in them, so this grows over the milestones in ROADMAP.md. What exists today:
src/
LakeWright.Core/ tenancy and job contracts
LakeWright.Databricks/ tenant-scoped Databricks SQL and job access
LakeWright.Multitenancy/ tenant model, resolution, operations, audit, EF Core
LakeWright.AspNetCore/ tenant middleware, role policies, operations API
LakeWright.AI/ Databricks model serving as an IChatClient, optional
LakeWright.Embedding/ scoped tokens for AI/BI dashboards, optional
LakeWright.Conversations/ tenant-scoped Genie, optional
samples/
Signalboard/ two-tenant sample product, Blazor dashboard plus the API
tests/
LakeWright.TenantIsolation.Tests/ the suite the rest of it rests on
databricks/ Declarative Automation Bundle, dev and prod targets
docs/ see docs/README.md
LakeWright.Multitenancy does not reference LakeWright.Databricks, so adopting the tenancy tier
alone does not drag in the Databricks client. A test enforces that rather than a convention.
Still to come: an observability export, per-tenant cost attribution in currency, and a reference deployment.
docs/README.md is the index. The ones most people want:
| Document | What it answers |
|---|---|
| Getting started | Running the tests, and wiring it into an application |
| Architecture | The three planes, what lives where, and why |
| Tenant model | The isolation decision matrix and the recommended default |
| Threat model | What is protected, from what, and which threats are unmitigated |
| Compatibility | Verified against a live workspace, versus taken from documentation |
| SOC 2 mapping | Which controls exist, which are partial, and which are the adopter's problem |
| Testing isolation | How the isolation suite is shown to fail when isolation is broken |
| Decisions | One record per load-bearing choice |
| Roadmap | What is next, what is open, and what nobody has checked |
This is a community project maintained in personal time. It is provided for your exploration only, it carries no service-level agreement, and it is provided as-is without warranties or guarantees of any kind. Do not open Databricks support tickets about it.
docs/compatibility.md records which Databricks features have been verified against a live workspace and which have not. Anything not listed as verified should be treated as unverified.
Databricks is a trademark of Databricks, Inc. This project is not affiliated with, endorsed by, or sponsored by Databricks, Inc.
.NET is a trademark of Microsoft Corporation. This project is not affiliated with, endorsed by, or sponsored by Microsoft Corporation.
