Skip to main content
Version: 10 - Vanillekipferl

Role Based Access Control

Starting with version 6 access to your resources is controlled by Role Based Access Control (RBAC). Every identity wishing to create/read/update/delete any resource must have the correct privileges.

warning

It is possible for authenticated users to infer names of resources to which they are not authorized. Avoid personally identifiable information or other high-risk data in names.

important

Best practice is the principle of least privilege. We recommend to only grant identities the privileges absolutely necessary to their purpose.

To quickly get started using roles head over to the Bundle list and download the Default roles bundle.

Identities, Roles and Permissions

Identities can have one or more roles. Every role has a collection of permissions. Other than users there are also webhooks or the git integration, for a full list of identities please refer to the flow API overview.

note

To assign a role to a user, the user has to be created. For more on how to create and manage users refer to User & Role Management.

A permission for a role consists of three basic attributes:

  • project: Any of your projects
  • Table type: Any cloudomation resource
  • operation: CREATE/READ/UPDATE/DELETE

All of these can be left unassigned, which means that they won't restrict access based on them.

To restrict access to only one project a permission could be created with only the project set and all other attributes left unset. This way all operations on all resources are allowed for the specific project.

Similarly if a permission is created with only the DELETE operation set it would allow deleting of every record in all projects.

You can see which roles have access to a specific record, by navigating to the record in the UI and clicking on the access list icon.

Click on the access list icon to see what roles have access to a record

important

All identities have implicit permissions to read and write the own record. For example, a user can read and update the own user record without the need for an explicit permission to do so.

note

It is not possible to modify the organization admin role to prevent you from locking yourself out of the system.

The built-in organization admin role has one permission entry, where every attribute is left unset.

Creating Roles

There are a few ways to create roles and assign permissions to them:

User Interface

To create a role click on the top right of the user interface and choose Manage Users & Roles, in the Roles tab click on the button Add role. After the role has been created it can be given permissions by clicking the Add button in the permissions section.

Flow API

To create a role via the flow API the method System.role can be used

example
role = System.role('my-new-role').save()

Adding permissions to this role is similarly easy by calling role.add_permission

example
# my-new-role allows reading of files in every project
role.add_permission(project=None, record=flow_api.file.File, operation=flow_api.enums.Operation.READ)
# view all permissions of my-new-role
this.log(permissions=list(role.get_permissions()))

Assigning roles to identities

roles can be given to identities by three means:

User Interface

From the identity view

By clicking on the role-management button in the top right corner of an identity.

Add a role to an identity from the identity view

There is a checkbox propagate more on this later.

From the role view

Still in the user interface, you can navigate to a role. Click on "+ Add" to assign it to identities.

Add a role to an identity from the role view

Flow API

The resources identity and role both have the methods add_role and add_identity respectively. They both have a keyword argument propagate which enables or disables role inheritance.

example
import flow_api

def handler(system: flow_api.System, this: flow_api.Execution, inputs: dict):
my_webhook = system.webhook('my-existing-webhook')

# create a role which the webhook needs to run
my_role = system.role('my-new-role')
my_role.add_permission(project=None, record=flow_api.flow.Flow, operation=flow_api.enum.Operation.READ)
my_role.add_permission(project=None, record=flow_api.execution.Execution, operation=None)

my_webhook.add_role(my_role, propagate=False)
return this.success('added role to webhook')

Role Inheritance

Previous sections have already hinted at the concept of role inheritance. Since executions, webhooks, schedules and all other identities can perform every action a user can on the platform, it is important to be able to limit their access. An identity can drop some or all rights it currently has by either doing so explicitly or implicitly using the propagate flag.

Every identityrole mapping has an attribute: propagate. Any identity created by another will have all the roles of the creating identity where this propagate flag is True.

note

The propagate flag will also be set to True for all child identities which have obtained a role via this manner.

example

A user might have two roles:

  • user, propagate=False: All permissions the user needs for day-to-day operations.
  • automation, propagate=True: All permissions the started executions need.

When the user starts a flow script (ie. creates an execution) it will only have the automation role.

Overriding the default inheritance model

There might arise situations where the default inheritance might not be viable in all situations. Providing the desired roles explicitly is a way around this limitation.

Resources created directly by the user can be modified after being created in the UI.

The flow API provides a keyword argument roles on all function and method calls which create identities. It accepts a list of dictionaries with they keys name and propagate, where name should contain the name of the role to propagate.

note

It is not possible to propagate roles which the calling identity doesn't have.

example
import flow_api

def handler(system: flow_api.System, this: flow_api.Execution, inputs: dict):

# call `my-flow` and only give it `my-flow_s-role`.
# if this execution doesn't have the `my-flow_s-role` but
# permission to create roles and identities we can do the following
# to allow inheriting the role:
this.add_role('my-flow_s-role', propagate=False)
this.flow(
'my-flow',
roles=[dict(name='my-flow_s-role', propagate=False)],
)
return this.success('all done')

Patterns

Webhooks and Schedules

Since webhooks and schedules are also identities they will give roles to executions created by them.

To work such identities need to have permissions to read all resources required by themself. A webhook will need to read the flow which gets executed and be able to create executions. The started execution might require a totally different set of permissions.

This can be modeled by giving the webhook two roles, one for the webhook itself and another one for the created execution(s), where the webhook role has propagate set to False.

Add two roles to the webhook

warning

It is possible to render a webhook, or for that matter any identity, unusable by giving it insufficient permissions. Care should be taken that they have all required permissions during configuration.

Connections

If connections reference vault secrets the identity creating these must also have read permission on the vault configuration.

Bundles

Access to resources in bundles is controlled by setting permission for the record type BUNDLE. This means that if you have read permission for the record type BUNDLE you will be able to read all resources that are associated with any bundle.

note

In order for a bundle permission to work correctly, the project of the permission should be set to "All Projects".

note

Bundles are read-only by nature. However, if you have permission for all operations on bundles you can remove the read-only flag and modify bundle content.