From dc24e482d80ce12e16dbdf43c76047ccf67554f3 Mon Sep 17 00:00:00 2001 From: Andres Aguiar Date: Sun, 8 Sep 2024 16:51:22 -0500 Subject: [PATCH] feat: added a multi-tenant RBAC advanced example --- stores/multitenant-rbac/README.md | 20 +++ stores/multitenant-rbac/store.fga.yaml | 176 +++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 stores/multitenant-rbac/README.md create mode 100644 stores/multitenant-rbac/store.fga.yaml diff --git a/stores/multitenant-rbac/README.md b/stores/multitenant-rbac/README.md new file mode 100644 index 0000000..0d5405d --- /dev/null +++ b/stores/multitenant-rbac/README.md @@ -0,0 +1,20 @@ +# OpenFGA Multi-Tenant Role Based Access Example + +## Use-Case + +This example demonstrates how to implement an advanced Role Based Access Control scenario for a B2B application, which the following requirements: + +- **Multi-tenancy**: You can define multiple tenants, modeled as `organizations`. Each tenant can have their own users, groups, roles and resources. +- **Predefined roles**: Each organization has an 'admin' role that can't be removed +- **Custom roles**: Each organization can define additional roles +- **Nested groups**: You can assign user to groups, and specify that all members of a group are members of another group. +- **Role<->Group assignment**: Roles can be assigned to individual users, members of a group users, or to assignees of a different role. +- **Coarse grained resource access**: Access to the organization's resource is defined purely on roles. In this example we do not allow defining fine-grained permissions per document, to showcase how OpenFGA provides significant value even if you don't need fine-grained permissions. + +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). + +## Try It Out + +1. Make sure you have the [FGA CLI](https://github.com/openfga/cli/?tab=readme-ov-file#installation) + +2. In the `multi-tenant-rbac` directory, run `fga model test --tests store.fga.yaml` diff --git a/stores/multitenant-rbac/store.fga.yaml b/stores/multitenant-rbac/store.fga.yaml new file mode 100644 index 0000000..38f5c44 --- /dev/null +++ b/stores/multitenant-rbac/store.fga.yaml @@ -0,0 +1,176 @@ +model: | + model + schema 1.1 + + type user + + # Groups can be nested + type group + relations + define member: [user, group#member] + + # Roles can be nested, and can be assigned to users and group members + type role + relations + define assignee: [user, role#assignee, group#member] + + type organization + relations + # Organizations can have predefined ones, in addition of dynamic roles + # that can be defined by each organization + define admin: [user, role#assignee] + + # These roles can be assigned to a dynamic role, and all admins inherit it too. + define user_manager: [role#assignee] or admin + define billing_manager: [role#assignee] or admin + define document_manager: [role#assignee] or admin + define document_viewer: [role#assignee] or admin + + define can_invite_user: user_manager + define can_delete_user: user_manager + define can_edit_billing: billing_manager + define can_create_document: document_manager + + type document + relations + # documents belong to an organization + define organization: [organization] + + # all permissions are inherited through the organization's roles + define editor: document_manager from organization + define viewer: document_viewer from organization + + define can_view: viewer or editor + define can_edit: editor + define can_delete: editor + +tuples: + # Anne is defined as an admin, using the predefined admin role at the organization level + + - user: user:anne + relation: admin + object: organization:acme + + # Francis, Ian and Emily are assigned to different Acme groups + + - user: user:francis + relation: member + object: group:acme-finance + + - user: user:ian + relation: member + object: group:acme-it-admins + + - user: user:emily + relation: member + object: group:acme-data-engineering + + # The data-engineering group is part of the engineering group. All members + # of data engineering are members of engineering + + - user: group:acme-data-engineering#member + relation: member + object: group:engineering + + # Group members are assigned to different Acme roles + + - user: group:acme-it-admins#member + relation: assignee + object: role:acme-admins + + - user: group:acme-finance#member + relation: assignee + object: role:acme-billing-manager + + - user: group:engineering#member + relation: assignee + object: role:acme-document-management + + # Role assignees are assigned to different pre-defined roles in the + # Acme organization + + - user: role:acme-admins#assignee + relation: admin + object: organization:acme + + - user: role:acme-billing-manager#assignee + relation: billing_manager + object: organization:acme + + - user: role:acme-document-management#assignee + relation: document_manager + object: organization:acme + + # The readme document belongs to the Acme organization + - user: organization:acme + relation: organization + object: document:readme + +tests: + - name: Test document permissions for each user + check: + # Emily is in Engineering and they have document-management role at Acme + - user: user:emily + object: document:readme + assertions: + can_edit : true + can_view : true + + # Anne is an admin + - user: user:anne + object: document:readme + assertions: + can_edit : true + can_view: true + + # Ian is an IT-Admin and they are admins at Acme + - user: user:ian + object: document:readme + assertions: + can_edit : true + can_view: true + + # Francis is in the Finance group and they can't manage documents + - user: user:francis + object: document:readme + assertions: + can_edit : false + can_view: true + + - name: Test billing permissions for each user + check: + # Francis is a member of the Finance group + - user: user:francis + object: organization:acme + assertions: + can_edit_billing : true + + # Ian is an IT-admin and IT-admins are admins + - user: user:ian + object: organization:acme + assertions: + can_edit_billing : true + + # Anne is an admin + - user: user:anne + object: organization:acme + assertions: + can_edit_billing : true + + # Emily is in Engineering + - user: user:emily + object: organization:acme + assertions: + can_edit_billing : false + + - name: Test all the users that can view document:readme + list_users: + - object: document:readme + user_filter: + - type: user + assertions: + can_view: + users: + # all users but Francis can view the document + - user:emily + - user:anne \ No newline at end of file