Authorization 101: Multi-tenant RBAC

Sep 9th, 2024

Omri Gazitt avatar

Omri Gazitt

RBAC  |  

Authorization

multi-tenant RBAC

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:

  1. Each tenant gets its own database - maximum isolation, least efficient.
  2. Each tenant gets its own schema - reasonable isolation, can scale to hundreds of tenants.
  3. 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.

multi-tenant RBAC manifest

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

citadel tenant object graph

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.

evaluator check morty 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:

search for resources

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!

Omri Gazitt avatar

Omri Gazitt

CEO, Aserto