Skip to content

LakeWright.NET

CI License .NET OpenSSF Best Practices OpenSSF Scorecard

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.

The Signalboard sample dashboard

Run it

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 up

Open 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.

What problem this solves

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.

What this is not

  • Not a Databricks SDK. Microsoft.Azure.Databricks.Client already 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.Embedding brokers 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.

Why the application runs outside Databricks

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.

Planned repository layout

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.

Documentation

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

Support boundary

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.

Trademarks

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.

License

Apache-2.0.

About

The build kit for multi-tenant .NET SaaS on Databricks. Reference architecture and reusable components for .NET teams selling analytics to customers who are not Databricks customers.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages