Access control
Corteza defines a RBAC access control facility. RBAC uses the roles of the given user to determine if they have access to the given resource.
The access control facility should be invoked whenever an identity is trying to access a protected resource. The only exception are resources that are only accessed by the system itself, such as settings, configuration options, and other system metadata.
DevNote some diagrams outlining the different flows |
Structure overview
pkg/rbac
RBAC rules are loaded into memory and accessed from there. The store layer is only involved when loading, reloading, or updating RBAC rules. |
pkg/rbac
contains the core logic, later referenced by other components and their services.
-
rbac.service
(struct): encapsulates rule management and access control check logic. Initialized withrbac.NewService(…)
. A singleton can be initialized withrbac.SetGlobal(…)
and accessed withrbac.Global()
. -
rbac.Resource
(interface): a generic interface for a more structured resource handling -
rbac.Session
(interface): a security session interface for a specific user-roles combinations. Predefined structures can be initialized withrbac.ContextToSession(…)
orrbac.NewSession(…)
.
<component>/service
Each components' service defines an accessControl
struct that is generated from def/\*.yaml
files.
See the Extending sub-sections for more details.
The accessControl
struct defines all resources and operations relevant to the given component and serves as a proxy to the internal pkg/rbac.Service
.
The accessControl
struct also performs grant action logging, validation, and access control.
Extending
Add a new resource
To add an entirely new resource, define a new file in the /def
directory.
The file should follow the pattern of: {component}(.{resource}).yaml
.
For example: system.user.yaml
.
If you’re defining component-level rules, omit the (.{resource})
part.
For example: system.yaml
.
rbac:
operations:
{operation}:
description: {optional notes here}
This uses the new WIP codegen v3; run with |
Add new rules to existing resources
To add a new rule to an existing resource, navigate the file in the /def
directory.
The file should follow the pattern of: {component}(.{resource}).yaml
.
For example: system.user.yaml
.
If you’re defining component-level rules, omit the (.{resource})
part.
For example: system.yaml
.
If the file does not yet exist, create it.
Add entry under rbac.operations
rbac:
operations:
{operation}:
description: {optional notes here}
This uses the new WIP codegen v3; run with |
Role types
List of roles for the bypass, authenticated, and anonymous type can not be changed at runtime. These roles can not be modified or renamed. If a role is assigned as a bypass, it may not appear as any other role type (such as an authenticated or anonymous). In the case where this is not the case, Corteza will refuse to start. |
Bypass
Bypass roles allow their members unlimited access to Corteza with no permission checking.
The list of bypass roles is defined in the RBAC_BYPASS_ROLES
.env
variable and can not be changed during runtime.
The default role is super-admin
.
Common
Common roles are any additional roles defined in the administration panel, such as a CRM admin and application builder.
Contextual
Contextual roles define a series of expressions, which determine when the role is assigned to the user based on the operations' context.
Each role can define an expression for each resource type. Each role can only use a resource type once.
An example use case would allow us to assign roles to resource owners, which would give them permissions that they shouldn’t have over other resources.
Role importance
Role importance specifies the order in which the provided roles and their corresponding rules are evaluated.
-
bypass roles
-
context roles
-
common roles
-
authenticated roles
-
anonymous roles
Resource identifiers
{rbac-ns}:: (1)
{component}: (2)
{service} (3)
{path} (4)
1 | The RBAC namespace allows us to group RBAC rules based on the area, allowing us to support custom rules in the future.
The namespace must match te regex of [a-z]* |
2 | The component must match te regex of [a-z]* |
3 | The service must match te regex of [a-zA-Z]+ |
4 | The path must follow the pattern of (/[*,a-z,A-Z,0-9]\*)+ |
When defining resource identifiers, the n-th path item must be more or equally specific to the (n+1)-th path item.
The following example is invalid, as the first item is less specific (wildcard *
) than the second one: corteza::compose:record/\*/21/2
.
Resource specificity
Resource specificity defines the order in which rules for the corresponding resources are evaluated. Resource specificity is defined based on "how specific is this rule to this resource".
As an example, a rule that allows users to create records on the account module in the CRM namespace is more specific than the rule just on the CRM namespace.
Under the hood, this is calculated based on the number of wildcard characters (*
) in the resource definition.
If the resource has no wildcard characters, the level is 0.
If the resource has n wildcard characters, the level is n-1 (0-based).
Example resource identifiers
- Compose component permissions
-
corteza::compose/
- Permissions for any namespace (level=1)
-
corteza::compose:namespace:/*
- Permissions for a specific namespace (level=0)
-
corteza::compose:namespace:/42
- Permissions for all records on a specific namespace (level=2)
-
corteza::compose:record/42/*/*
- Permissions for all records on a any namespace or any module (level=3)
-
corteza::compose:record/*/*/*
- Permissions for a specific record (level=0)
-
corteza::compose:record/42/21/2
- Permissions for record values on a specific module fields (level=0)
-
corteza::compose:moduleField/42/21/12
Access evaluation flow
The access is evaluated based on the security context (namely the role importance and resource specificity) and the operation they are trying to perform.
-
If any rule defines an explicit deny, the evaluation results with deny.
-
If at least one rule defines an explicit allow, the evaluation results with allow.
-
If the current level has no explicit allow or deny, the evaluation continues to the next set of rules based on role importance.
-
If the evaluation cannot find an explicit allow or deny, the evaluation results with deny.
Glossary
A user is an entity that is accessing Corteza. A user can be a member of security roles and cannot get permissions directly without an assigned role. |
|
A role represents a set of users and a set of permissions over resources. Corteza’s RBAC implementation defines a flat structure that removes role hierarchy (two roles can not explicitly specify a parent/child relationship). |
|
Defines if the rule permits ( |
|
A structured piece of information stored within Corteza that we may or may not control access to. Each resource belongs to a component and has a unique type. |
|
A resource type defines the structure of information within the Corteza component. |
|
Defines what operation the given RBAC rule defines access to. |
|
A RBAC rule combines operation, role, access, and resource. It defines what someone can (or can not) do on one or more resources inside Corteza. |
|
A security session is created when a user requests to access Corteza. |