Auth & identity
January 29, 2024
Author: Isaac Ejeh
When it comes to assigning user permissions based on who should have the rights to do what and why, RBAC is a flexible way to enforce access control and security according to designated roles.
With RBAC, you can categorize users as administrators or restricted users at varying levels of hierarchy. Administrators have unlimited access to all resources and can perform any action on them. While restricted users have limited access and can only perform restricted actions on specific resources.
Administrators can easily reassign users between different roles in response to security threats and changing business requirements. They can also add new users to roles as required within the system, and also revoke permissions from users who no longer belong to certain roles.
In RBAC architectures, roles are a collection of permissions that are assigned to a user or group of users, whether human users or service accounts. While permissions determine the actions these users are allowed to perform on resources.
In other words, permissions aren’t assigned to users directly. Rather, system administrators create roles and map specific permissions to those roles. Users are then assigned to roles based on the functions they’re required to perform within the system. This way, authorized users gain access by inheriting the permissions of the roles to which they belong.
Roles can be organized hierarchically, such that if a Beneficial Owner role is higher than a Bookkeeper role in the hierarchy, the Beneficial Owner will inherit the permissions of the Bookkeeper role. However, the Bookkeeper role will not inherit the permissions of the Beneficial Owner role which is senior in hierarchy.
This hierarchical structure of RBAC, as well as other implementation structures within RBAC, make it an ideal access control architecture for managing security in all types of software resources, including applications, computer networks, APIs, virtual machines, and microservices. We will discuss these implementation structures in detail later in this article.
RBAC authorization is widely used by organizations of all sizes, from small and medium-sized businesses to large, multi-tenant SaaS companies. These SaaS providers typically manage access rights and permissions for large user bases across multiple tenants. As such, managing the multitude of relationships between roles and permissions in multi-tenant SaaS architectures can be quite complex.
To illustrate, let’s consider a project management SaaS that’s designed to enable teams to collaborate on projects — for example, Asana, Jira, Monday, Basecamp, Linear, or any other alternative that emphasizes the point. Users in this multi-tenant SaaS can assume roles such as project managers, team members, or workspace administrators, each requiring distinct access rights.
Project managers need to be able to create and assign tasks, view and edit project timelines, and communicate with team members. Team members need to be able to view and edit their tasks, as well as communicate with project managers and other team members. While Administrators need to be able to view and edit all workspace data, as well as manage user permissions.
Now, even for the same role, permissions can differ across tenants. A particular role may have varying privileges in one tenant compared to another tenant, granting it unique access rights in each context.
For instance, project managers in one tenant might have the ability to create and assign tasks, while those in another tenant may only be allowed to create tasks by their workspace administrator. This dynamic scenario highlights one of the intricate challenges involved in managing RBAC within a typical multi-tenant SaaS architecture.
That is why SaaS engineering teams typically rely on identity providers like Stytch to implement robust role-based access control (RBAC) architectures in weeks. It eliminates the security risks and development resources involved with managing an in-house RBAC solution, allowing teams to go to market faster.
In this article, we’ll explore role-based access control (RBAC), how it works, its core tenets and principles, practical applications of the RBAC model, implementation challenges and best practices, and how all of this might fit within a typical B2B SaaS application.
RBAC is a flexible security architecture. It doesn’t impose any specific security policies on organizations that adopt the model. Rather, it provides a framework for organizations to build access control systems that align with their internal security policies and requirements. This flexibility is probably one of the reasons why RBAC is so popular.
Role-based access control (RBAC) is based upon several industry-wide security principles, including data abstraction, least privilege, and separation of duties. These principles are not mutually exclusive; they work together synergistically to deliver robust and secure access control architectures.
Data abstraction: Instead of assigning permissions directly to users, RBAC uses roles to group related permissions together. These roles act as abstractions, hiding the underlying intricacies of individual permissions and access rights. This abstraction helps in creating a more organized structure for understanding what each user can do, making it easier to manage access control within organizations of any size.
Least privilege: In RBAC, users are assigned only the roles that grant them the least amount of permissions necessary to perform their designated functions. This least-privilege approach reduces your attack surface in the event of a potential security breach by limiting the amount of access an attacker can potentially have.
Separation of duties: RBAC leverages the principle of separation of duties to ensure that no single user has complete control over critical parts of an RBAC system. Sensitive functions are assigned to different roles, and approval requires the consent of multiple users. This provides an extra layer of security and accountability, and is consistent with regulatory and statutory requirements/best practices.
RBAC is well-known for its centralized and non-discretionary (NDAC) approach to access management, which sets it apart from discretionary access control (DAC) and even mandatory access control (MAC).
In non-discretionary access control (NDAC), authorization decisions are generally made by a system administrator or security policies that govern the system. As such, control is not left to the discretion or preferences of individual resource owners. Users don’t have authority over the resources they are allowed to access and are unable to transfer rights or resources to other users.
In contrast to NDAC, access control is decentralized in DAC. Resource owners have full discretion and control over who is granted access to a resource and what level of access they should have. A resource owner can decide whether to have the sole right to grant access to any particular resource or delegate that right to other users.
DAC uses access control lists (ACLs) to restrict access to resources, such as computer networks, files, and databases. ACLs define which users have access to a resource and what privileges they have for that resource. ACLs such as filesystem ACLs can be used to manage access to files, directories, or databases while networking ACLs can be used to restrict network access and what activities are allowed.
So far, we’ve explored three industry-wide security principles that RBAC is based upon: (i) Data abstraction (ii) Least privilege (iii) Separation of duties. When it comes to RBAC specifically, the framework is built on three other fundamental principles that serve as its core tenets.
Different engineering, IT, and security teams may implement these principles in varying ways depending on their specific use cases. However, these underlying principles remain consistent across these organizations:
By now, you should be familiar with the concept of roles and permissions in RBAC. Essentially, roles determine authorization within an RBAC system, so it’s important to define them properly.
Roles in RBAC are very different from conventional cohorts or groups. While groups are a collection or cohort of users who share common attributes, roles embody permissions and can vary widely in scope.
A role is a collection of permissions that define the operations that can be performed on specific resources within a system. Permissions determine the actions that a user can perform, as dictated by their assigned role. These permissions typically include read, write, or delete operations, and roles can be assigned to users or groups of users who require similar permissions.
For instance, roles can range from high-level designations such as a workspace administrator, to more specific roles that can inherited by multiple users, such as a bookkeeper role.
By assigning permissions to roles rather than individual users, administrators can efficiently manage how they grant or revoke access without manually configuring permissions for each user. Over time, roles become increasingly valuable as your user base grows and technical requirements evolve.
When a user is assigned multiple roles with similar or overlapping permissions in an RBAC system, they effectively inherit a combination of all the permissions associated with each role. In other words, the user gains a comprehensive set of permissions drawn from all the roles they’ve been assigned.
For example, let’s consider a content management system (CMS) where a single user is assigned two distinct roles: “Content Manager” and “Publisher.” If the “Content Manager” role grants the user permission to manage CMS settings, while the “Publisher” role allows them to publish article drafts, they would effectively possess these combined user privileges. In essence, the user would have the ability to manage the CMS and also publish drafts directly, reflecting their expanded set of permissions granted by the overlapping roles.
However, it’s important to note that RBAC restricts users from activating all of their assigned roles simultaneously. Users can only activate a subset of their roles during a single session. This approach provides flexibility, allowing users to choose and activate only the roles relevant to the specific operations they need to perform in a particular session.
The National Institute of Standards and Technology (NIST) model for role-based access control (RBAC) outlines four incremental implementation levels for RBAC. These levels guide the incorporation of roles, permissions, sessions, and other components within RBAC architectures. Each level builds upon the requirements of the previous level, offering increased functionality and complexity:
Flat RBAC is the most basic level of RBAC implementation. At this level, roles are assigned permissions, and users are subsequently assigned those roles. There is no hierarchical structure for roles, and users gain the necessary permissions solely by acquiring roles within the system.
Flat RBAC acknowledges the many-to-many relationships that can exist between users and roles, allowing a single user to be assigned multiple roles and, as a result, multiple permissions. Similarly, multiple users can be assigned to the same role.
Hierarchical RBAC adds hierarchy to the role structure in flat RBAC. Roles are defined based on hierarchical levels, such that higher-level roles inherit the permissions of lower-level roles, in addition to their privileges. However, the permissions of a higher-level role cannot be inherited by any of its child roles.
In hierarchical RBAC, access control can be implemented via three main relationship structures: (i) Tree structure (ii) Inverted-tree (iii) Partial order.
In the tree-like relationship structure, roles are organized in a rigid hierarchical structure, resembling a tree. Each role has one parent (except for the top role) and can potentially have multiple child roles. This parent-child relationship establishes a strict hierarchy between roles, which may not accurately reflect complex organizational structures where roles may overlap or have conflicting interests.
In partial order, the role structure is not strictly hierarchical. While roles can have relationships, they are not confined to a strict parent-child structure. Some roles might have a partial order relationship, indicating a level of precedence or association, but not every role is required to have a direct predecessor or successor. This allows for a more flexible arrangement of roles based on the contextual relationships within organizations of different sizes.
Constrained RBAC extends the hierarchical model by incorporating constraints, such as separation of duties (SoD) enforced during user/role assignment and role authorization in user sessions. The separation of duties (SoD) principle is implemented within the constrained RBAC model to mitigate the risks associated with overprivileged users and potential conflicts of interest. It can be enforced in two primary modes: Static SoD (SSoD) and Dynamic SoD (DSoD).
In SSoD, a user cannot simultaneously hold roles with overlapping principles, ensuring that no single user possesses mutually exclusive roles. In contrast, DSoD permits a user to be a member of conflicting roles, but they cannot exercise both roles during the same session.
Symmetric RBAC extends the other three RBAC implementation levels by incorporating the ability to review permissions associated with roles. In this way, security administrators can identify roles with more privileges than required, or roles lacking the necessary permissions to fulfill their designated functions.
Slack is the workplace messaging platform that enables teams to send files and instant messages about work, and was acquired by Salesforce for ~$28 billion.
Several years ago at Slack, the engineering team discovered that their predefined user roles were overly broad. This led to users having excessive privileges and power, particularly in large enterprise organizations.
At the time, assigning the Admin role to non-administrators led to complications when they had to carry out their specialized functions originally associated with the Admin role. This role granted them administrative-level capabilities, enabling lower-ranking users to perform actions beyond their seniority level within a Slack workspace.
For instance, if you assigned the Admin role to a member to have them manage a channel, they were able to perform other admin-level actions that were beyond the typical job function of a channel/community manager.
To tackle this problem of overprivileged users, Slack’s engineering team first conducted a thorough review of their roles and permissions structure, as it were. Their primary goal was to break down the extensive capabilities of the Admin role into three specialized and manageable system roles within a new RBAC system, namely: Roles admin, Users admin, and Channels admin.
Initially, the Admin role could perform a wide range of administrative functions within Slack, including inviting new users, configuring preferences, installing external applications, managing channels, and overseeing various parts of the workspace.
However, after the Admin role was broken down, newer admin roles were introduced, each with a unique set of permissions and responsibilities within Slack:
Roles admin: Users assigned to this role can manage and administer roles within an organization on Slack. They can assign users to different roles, modify role permissions, and ensure that the appropriate level of access is granted to each individual.
Users admin: Users assigned to this role can add and remove users from the Slack workspace. They can also manage user groups, which are collections of users with similar roles or responsibilities within the organization.
Channels admin: This admin is responsible for managing channels within the organization. They can edit channels, archive channels, create private channels, and switch public channels into private ones.
In Slack’s revamped RBAC architecture, when a user authenticates to a role, the RBAC service checks their permissions by querying their role information from the data store. This interaction between Slack’s web app and the RBAC service is facilitated by a dedicated remote procedure call (RPC) protocol.
By decoupling the RBAC service from the web app, Slack was able to manage permissions more efficiently, even at scale. Engineering and security teams could seamlessly add new roles and permissions, reducing the risk of inadvertently altering business logic or compromising the application’s performance and availability.
In multi-tenant architectural models, multiple organizations (tenants) concurrently share the same software instance or cloud compute. However, in such scenarios, coarse-grained access control (CGAC) models like RBAC may not guarantee complete isolation of tenant data, especially at scale.
SaaS applications are designed to efficiently serve large user bases by sharing resources such as infrastructure, code, and databases across multiple tenants. This multi-tenancy approach allows SaaS engineering teams to build scalable pipelines without having to dedicate extensive resources to each tenant.
To illustrate multi-tenancy, let’s consider a shared office building where multiple businesses operate independently. Each business leases its own space within the office building, but they all have to share common facilities like elevators, security services, and lounges. While they share the same physical infrastructure, these businesses operate in isolation, maintaining strict separation and autonomy.
They have distinct offices, confidential files, business models, and operations. Employees from one business don’t have access to the sensitive information or secrets of another, and each business operates in isolation.
This office building scenario closely resembles a typical multi-tenant SaaS architecture. In a multi-tenant SaaS architecture, each customer or tenant has their own dedicated and isolated portion of shared resources. This segregation ensures that each tenant’s data remains confidential and isolated, and that the actions of one tenant do not affect the operations of another tenant.
While tenants can’t access each other’s data, all tenant data is stored in the same database, and the same codebases/clusters process all the shared code and functionality. Nonetheless, each tenant can individually configure their portions of the application according to their unique requirements.
On the other hand, as multi-tenant applications grow in size and complexity, it becomes increasingly difficult to meet the unique requirements of each organization. Similar to our Slack example, SaaS applications typically provision a set of predefined roles that can be assigned to users, but these roles can become too rigid to accommodate the varying requirements within each organization.
As customers make specialized feature requests tailored to their unique use cases, SaaS engineering teams often try to accommodate them by creating highly specific roles for these individual tenants.
However, this approach can be problematic because RBAC roles are static and have a fixed set of permissions. Over time, this will inevitably lead to role explosion, where the substantial number of roles makes it highly complex to manage authorization logic across all tenants.
To implement dynamic access control without having to create specialized or specific roles, SaaS companies typically utilize fine-grained access control (FGAC) models such as ABAC (based on attributes) and PBAC (based on policies). By leveraging these models, SaaS companies can build hybrid security architectures that accommodate granular use cases, providing more flexibility and control across multiple tenants.
Unlike RBAC architectures that solely grant or deny user access based on the permissions within predefined roles, attribute-based access control (ABAC) leverages a combination of attributes to determine access decisions, and roles can be one of these attributes.
In hybrid architectures, ABAC attributes can be used in conjunction with RBAC to implement dynamic access control, without having to create additional roles. These attributes can be user attributes (e.g., user ID, role, organization, country), resource attributes (e.g., the date a resource was created), or environment attributes (e.g., the device from which a user request is originating).
To implement RBAC + ABAC, you have to incorporate your RBAC role as a user attribute within ABAC. In this way, you can use RBAC to enforce fundamental access control rules like role hierarchy, separation of duties, and least privilege. Then, you can use attributes within ABAC to further restrict access permissions based on your specific requirements.
For example, let’s consider an RBAC “Manager” role that has been assigned to perform CRUD operations on system resources. We can incorporate ABAC in this scenario by using department attributes to restrict users in the “Manager” role who also belong to the “Engineering” department to only manage engineering-related resources.
Alternatively, multi-tenant companies with more complex access control requirements can choose to implement an RBAC + ABAC + PBAC hybrid architecture. Instead of relying solely on user roles or attributes, policy-based access control (PBAC) leverages predefined policies and rules to dynamically grant or deny access to protected resources.
However, to successfully implement a hybrid architecture, your team must have a comprehensive understanding of your organization’s security policies and regulatory framework. This kind of endeavor typically requires active collaboration from a wide range of stakeholders across the organization, including DevSecOps, data teams, IT administrators, engineering teams, and even product teams.
Stytch provides a flexible RBAC product that’s designed to accommodate complex authorization requirements within multi-tenant architectures. Whether you’re looking to enforce robust access control in B2B, B2B2C, or B2B2B SaaS applications, we built our RBAC solution with your use case in mind.
With Stytch’s API, you can programmatically assign roles and orchestrate access control, eliminating the need to manually grant permissions one by one. Each role carries predefined permissions that members inherit and retain unless their role is explicitly revoked within the Stytch platform.
Stytch also supports implicit role assignment, where members are automatically assigned roles based on specific criteria or attributes. This mechanism allows you to define rules for automatically assigning roles to multiple members at once.
Want to see how you can implement RBAC with Stytch? Check out our documentation and sign up for a free developer account to start building with our easy-to-integrate APIs today. If you have any questions, please reach out to us at firstname.lastname@example.org or schedule a chat with a member of our team.