Every multi-tenant B2B SaaS product needs an authorization model that meets two fundamental requirements:
- The data for each tenant (typically a company) must be isolated from every other tenant.
- Within each tenant, users should be restricted to capabilities and data that match their role.
Multi-tenancy using your database
These requirements aren’t hard to implement using a simple database design. Tenancy can be implemented in a few different ways, as Craig eloquently describes here:
- Each tenant gets its own database - maximum isolation, least efficient.
- Each tenant gets its own schema - reasonable isolation, can scale to hundreds of tenants.
- Each table has a tenant column - isolation must be implemented in SQL, but scales to tens of thousands of tenants.
For the third option, the database can help - for example, you can use row-level security (RLS) to enforce a policy for various types of users across different actions (SELECT, UPDATE, etc).
When do you need an authorization platform?
But every database-centric authorization approach eventually runs out of rope. Here are a few examples of new requirements that will lead to a costly redesign of your database schema:
- You need to add another layer of containment under tenants - for example, teams or projects.
- You need to support sharing of resources (e.g. an owner of an object wants to make another user be able to view or edit this object).
- You need to support cross-cutting roles across tenants - for example, an “accountant” role isn’t a member of a specific tenant, but could have “view” access to financial data across a set of tenants that they serve.
A better approach to multi-tenant RBAC is to start with an authorization platform like Topaz, and evolve your authorization model as your requirements grow, instead of having to rip and replace your permissioning system over and over.
The Topaz multi-tenant RBAC template
To make this easy, Topaz has a multi-tenant RBAC template that models the following types:
- A “system”, which allows global admins to create tenants.
- A “tenant”, which scopes resources and has various roles that allow managing the tenant, and creating, deleting, updating, and reading resources inside of that tenant.
- A “resource”, which is scoped to a tenant and has various roles that allow reading, updating, or deleting that resource.
types:
# system represents the entire application and grants access to all tenants
system:
relations:
admin: user | group#member
editor: user | group#member
viewer: user | group#member
permissions:
can_create_tenant: admin
# tenant represents a tenant in a multi-tenant system
tenant:
relations:
# system that the tenant is part of.
system: system
owner: user
admin: user | group#member
editor: user | group#member
viewer: user | group#member
permissions:
# group members into 3 high-level categories: can_administer, can_edit, can_view.
# these are used to define fine-grained permission.
can_administer: owner | admin | system->admin
can_edit: editor | can_administer | system->editor
can_view: viewer | can_edit | system->viewer
# fine-grained permissions make it easier to change access levels without
# modifying application logic.
can_delete_tenant: owner | system->admin
can_manage_members: can_administer
can_list_members: can_view
# an owner cannot leave the tenant. they must be removed by another owner.
can_leave_tenant: can_view - owner
can_create_resources: can_edit
can_delete_resources: can_administer
can_write_resources: can_edit
can_read_resources: can_view
# resource represents a resource within a tenant
resource:
relations:
# tenant that the resource is part of.
tenant: tenant
owner: user
writer: user | group#member
reader: user | group#member
permissions:
can_delete: owner | tenant->can_delete_resources
can_write: writer | can_delete | tenant->can_write_resources
can_read: reader | can_write | tenant->can_read_resources
This is a good starting point for a multi-tenant RBAC system, which can easily be extended in the future to additional levels of hierarchy (projects or teams inside of tenants).
It also provides the underpinnings for sharing of resources, as well as granting permissions across tenants to cross-cutting roles.
To get started with the multi-tenant RBAC template in the Aserto Console, without installing anything, simply follow this QuickStart.
Or if you’d like to play around with the template using Topaz and its CLI, follow the steps below.
Install topaz
brew tap aserto-dev/tap && brew install topaz
Install the multi-tenant RBAC template
topaz templates install multi-tenant
You should now see the Topaz console in your browser.
Navigate relationships in the console
You can navigate to the Objects tab, and view the System, Tenants, and Resources objects and the relationships between them.
For example, click the “Tenant” object type in the Objects tab to see the two tenants, citadel
and smiths
. Click the citadel
tenant to see the Resource it contains (citadel-adventures
) and the relationships to users (Morty is an editor of the tenant, whereas Rick is the tenant owner).
Evaluate permissions in the evaluator
Use the Evaluator to check whether a user has a permission on a resource. In the screenshot below, we’re evaluating whether the user Morty has the can_read
permission on the citadel-adventures
resource.
Copy the API call as a cURL using the button in the top-right side of the Request pane to see how you’d call Topaz using its REST API (or use one of our many SDKs).
curl 'https://localhost:9393/api/v3/directory/check' \
-H 'aserto-tenant-id: ' \
-H 'authorization: ' \
-H 'content-type: application/json' \
--data-raw '{"subject_type":"user","subject_id":"morty@the-citadel.com","object_type":"resource","object_id":"citadel-adventures","relation":"can_read"}'
{
"check": true,
"trace": []
}
Determine who has access to what
Execute “search” calls to see what resources a user has access to, or what users can access a resource. For example, Morty has the can_read
permission on both the citadel-adventures
and the smiths-budget
resources, which are in two different tenants:
Conclusion
Multi-tenancy may seem deceptively simple to implement in your database, but you’ll quickly run out of room when the next set of requirements emerge. As you need to implement teams, projects, or other hierarchies, or have roles that cut across multiple tenants, or provide item level sharing, you’ll need to redesign your database system, often more than once!
To get off the database redesign train, you should adopt an authorization platform early in your journey. Topaz offers a multi-tenant RBAC template out of the box, and makes it easy to adapt and evolve it to your needs.
As an added benefit, an authorization platform like Topaz also makes it easy to answer questions like “which users have access to a resource”, or “what resources can a user access”. These are super helpful when you’re constructing a permission-aware UI.
Get started with Topaz today! And if you run into any issues, don’t hesitate to join our community slack or set up a meeting with one of our engineers.
Happy hacking!
Related Content
Implementing Custom Roles in your SaaS Application
Custom roles are tricky to implement. This post offers two approaches for allowing each tenant to add custom roles: one for simple RBAC, and one for fine-grained ReBAC.
Jun 20th, 2024
Building dynamic RBAC with custom roles for multi-tenant applications
At some point, your customers will start asking for specific roles to match their unique use-cases. Don't be tempted to build these 1:1 roles for them. The right solution would be to allow customers to create custom roles from the set of available permissions. Here's the best way to do that.
Apr 26th, 2023
RBAC vs ABAC: pros, cons, and example policies
RBAC and ABAC are two popular models for securing access to resources. Both models have their merits and both have limitations. Learn all about role-based and attribute-based access control and see example policies in this post.
Jan 11th, 2023