Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added a multi-tenant RBAC advanced example #36

Merged
merged 2 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions stores/multitenant-rbac/README.md
Original file line number Diff line number Diff line change
@@ -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`
176 changes: 176 additions & 0 deletions stores/multitenant-rbac/store.fga.yaml
Original file line number Diff line number Diff line change
@@ -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