Skip to content

Commit 4f6d6a1

Browse files
Merge branch 'main' into docs/update-openfga-v1.8.15
2 parents eb01fe0 + 3f4d874 commit 4f6d6a1

File tree

4 files changed

+357
-2
lines changed

4 files changed

+357
-2
lines changed
Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
---
2+
title: Modeling roles
3+
slug: /best-practices/modeling-roles
4+
description: Various ways of modeling static and dynamic roles in FGA - both coarse and fine-grained.
5+
sidebar_position: 1
6+
---
7+
import {
8+
ProductName,
9+
ProductNameFormat,
10+
RelatedSection,
11+
} from '@components/Docs';
12+
13+
# Modeling Roles
14+
15+
Roles are a common way to group users and assign permissions to those groups. They can be used to simplify permission management, especially in larger systems where many users have similar access needs.
16+
17+
In this guide, we'll explore common approaches to modeling roles with <ProductName format={ProductNameFormat.ShortForm}/>.
18+
19+
## When to Use Each Approach
20+
21+
Before diving into implementation details, here's a quick guide to help you choose the right approach:
22+
23+
| Approach | Best For | Complexity | Flexibility | Example
24+
|-------------------------------|------------------------------------|------------|-------------|--------------------------------------------------------------------------------------------------------------------|
25+
| **Relations as Roles** | Static, predefined roles | Low | Low | In all instances, company admins can view project information. |
26+
| **Simple User-Defined Roles** | User-defined roles at org level | Medium | Medium | Company Acme creates an "Auditor" role that is configured to view project information for all projects. |
27+
| **Role Assignments** | Instance-specific role assignments | High | High | In Company Acme, Anne can be a custom Auditor role for Projects 1 and 5, but Beth can be an Auditor on Project 3. |
28+
29+
## Approach 1: Relations as Roles
30+
31+
The simplest way to implement roles is to use directly assignable relations. They work well for roles that always exist and can be defined at development-time. Adding relations is straightforward, and you do not need to add roles very frequently. If roles are static, this is always the preferred approach.
32+
33+
### Example: Organization Admin Role
34+
35+
In the model below, we define an `admin` role at the organization level. Admins can edit billing details and create projects.
36+
37+
```dsl.openfga
38+
model
39+
schema 1.1
40+
41+
type user
42+
43+
type organization
44+
relations
45+
define admin: [user]
46+
define can_create_project: admin
47+
define can_edit_billing_details: admin
48+
```
49+
50+
### Adding Users to Roles
51+
52+
To add users to the admin role, create a tuple like:
53+
54+
```yaml
55+
- user: user:anne
56+
relation: admin
57+
object: organization:acme
58+
```
59+
60+
### Extending with Additional Roles
61+
62+
If later you need to add a `project_admin` role with permissions to view/edit projects, the model evolves to:
63+
64+
```dsl.openfga
65+
model
66+
schema 1.1
67+
68+
type user
69+
70+
type organization
71+
relations
72+
define admin: [user]
73+
define project_admin: [user] # new role
74+
75+
# existing permissions
76+
define can_edit_billing_details: admin
77+
define can_create_project: admin or project_admin
78+
79+
# new permissions for project admins
80+
define can_edit_project: admin or project_admin
81+
define can_view_project: admin or project_admin
82+
```
83+
84+
### Pros and Cons
85+
86+
**✅ Advantages:**
87+
- Simple to implement and understand
88+
- Fast evaluation performance
89+
- Clear authorization policies
90+
- No additional tuples needed when adding permissions
91+
- Role permissions are straightforward to change, regardless of scale
92+
93+
**❌ Disadvantages:**
94+
- Roles must be predefined in the model
95+
- Not suitable for user-defined roles
96+
97+
---
98+
99+
## Approach 2: Simple User-Defined Roles
100+
101+
Many applications require the flexibility for end-users to define their own custom roles, in addition to any pre-defined roles. This approach enables organizations to tailor permissions to their specific needs.
102+
103+
### Example: Custom Project Admin Role
104+
105+
With the following model, your application can support both static roles and user-defined roles:
106+
107+
```dsl.openfga
108+
model
109+
schema 1.1
110+
111+
type user
112+
113+
type role
114+
relations
115+
define assignee: [user]
116+
117+
type organization
118+
relations
119+
define admin: [user] # static role
120+
121+
# permissions can be assigned to custom roles or static roles
122+
define can_create_project: [role#assignee] or admin
123+
define can_edit_project: [role#assignee] or admin
124+
```
125+
126+
### Setting Up Custom Roles
127+
128+
1. **Define role permissions** by creating tuples that grant the role-specific permissions:
129+
130+
```yaml
131+
- user: role:acme-project-admin#assignee
132+
relation: can_create_project
133+
object: organization:acme
134+
135+
- user: role:acme-project-admin#assignee
136+
relation: can_edit_project
137+
object: organization:acme
138+
```
139+
140+
2. **Assign users to the role**:
141+
142+
```yaml
143+
- user: user:anne
144+
relation: assignee
145+
object: role:acme-project-admin
146+
```
147+
148+
### Adding New Permissions
149+
150+
When you add new permissions to your model, existing roles don't automatically receive them:
151+
152+
```dsl.openfga
153+
model
154+
schema 1.1
155+
156+
type user
157+
158+
type role
159+
relations
160+
define assignee: [user]
161+
162+
type organization
163+
relations
164+
define admin: [user]
165+
define can_create_project: [role#assignee] or admin
166+
define can_edit_project: [role#assignee] or admin
167+
define can_delete_project: [role#assignee] or admin # new permission
168+
```
169+
170+
To grant the new permission to existing roles, create additional tuples:
171+
172+
```yaml
173+
- user: role:acme-project-admin#assignee
174+
relation: can_delete_project
175+
object: organization:acme
176+
```
177+
178+
You do not need to add these tuples when adding the new permission. End-users will add the new permission to their custom roles when they find it appropriate.
179+
180+
### Pros and Cons
181+
182+
**✅ Advantages:**
183+
- Supports user-defined roles
184+
- Flexible permission assignment
185+
- No model changes needed for new role instances
186+
187+
**❌ Disadvantages:**
188+
- More complex than static relations
189+
- Requires additional tuples for role-permission mapping
190+
191+
---
192+
193+
## Approach 3: Role Assignments
194+
195+
The previous approach works well when custom roles are global for the organization. However, if you need roles that can be attached to different object instances with different members for each instance, you need role assignments.
196+
197+
### Example: Project-Specific Admin Roles
198+
199+
Let's say you want a "Project Admin" role where each project can have different admins, but the role permissions remain consistent.
200+
201+
### Step 1: Define the Role and its Permissions
202+
203+
Define a `role` type where you list all the permissions that any role can have:
204+
205+
```dsl.openfga
206+
model
207+
schema 1.1
208+
209+
type role
210+
relations
211+
define can_view_project: [user:*]
212+
define can_edit_project: [user:*]
213+
```
214+
215+
A "Project Admin" role can have `can_view_project` and `can_edit_project`:
216+
217+
```yaml
218+
# Project Admin role has both the can_view_project and can_edit_project assigned
219+
- user: user:*
220+
relation: can_view_project
221+
object: role:project-admin
222+
223+
- user: user:*
224+
relation: can_edit_project
225+
object: role:project-admin
226+
```
227+
228+
### Step 2: Assign Users to a Role on an Entity
229+
230+
Add a `role_assignment` type to assign users to the role:
231+
232+
```dsl.openfga
233+
type role_assignment
234+
relations
235+
define assignee: [user]
236+
define role: [role]
237+
238+
define can_view_project: assignee and can_view_project from role
239+
define can_edit_project: assignee and can_edit_project from role
240+
```
241+
242+
### Step 3: Connect to Your Objects
243+
244+
Define an `organization` type with an `admin` role. Then, define a `project` type that links to an `organization` and a `role_assignment`. Note that we are combining a static `admin` role with custom role assignments. We recommend to always use static roles when they are known in advance.
245+
246+
```dsl.openfga
247+
type organization
248+
relations
249+
define admin: [user]
250+
251+
type project
252+
relations
253+
define organization: [organization]
254+
define role_assignment: [role_assignment]
255+
256+
# combine role assignments and static roles
257+
define can_edit_project: can_edit_project from role_assignment or admin from organization
258+
define can_view_project: can_view_project from role_assignment or admin from organization
259+
```
260+
261+
### Setting Up Role Assignments
262+
263+
1. **Create the role assignment instance**:
264+
265+
```yaml
266+
- user: user:anne
267+
relation: assignee
268+
object: role_assignment:project-admin-openfga
269+
270+
- user: role:project-admin
271+
relation: role
272+
object: role_assignment:project-admin-openfga
273+
```
274+
275+
2. **Link the role assignment to the project**:
276+
277+
```yaml
278+
- user: role_assignment:project-admin-openfga
279+
relation: role_assignment
280+
object: project:openfga
281+
```
282+
3. **Link the project to an organization**:
283+
284+
```yaml
285+
- user: organization:acme
286+
relation: organization
287+
object: project:openfga
288+
```
289+
### Pros and Cons
290+
291+
**✅ Advantages:**
292+
- Maximum flexibility for instance-specific roles
293+
- Reusable role definitions across different objects
294+
- Fine-grained control over role membership
295+
296+
**❌ Disadvantages:**
297+
- Most complex approach to implement
298+
- Requires careful planning of the role hierarchy
299+
- More tuples needed for setup and maintenance
300+
301+
---
302+
303+
## Choosing the Right Approach
304+
305+
### Decision Tree
306+
307+
1. **Do you need user-defined roles?**
308+
- No → Use **Relations as Roles**
309+
- Yes → Continue to step 2
310+
311+
2. **Do roles need different members per object instance?**
312+
- No → Use **Simple User-Defined Roles**
313+
- Yes → Use **Role Assignments**
314+
315+
### Performance Considerations
316+
317+
- **Relations as Roles**: Fastest evaluation
318+
- ***Simple User-Defined Roles**: Moderate performance impact
319+
- **Role Assignments**: Highest performance impact
320+
321+
## Best Practices
322+
323+
1. **Start simple**: Begin with relations as roles and evolve as needed
324+
2. **Hybrid approach**: Combine static relations for well-known roles with dynamic roles for custom ones
325+
3. **Documentation**: Clearly document your role model for your team
326+
4. **Functional Testing**: [Write tests](../modeling/testing-models.mdx) to verify your model behaves as expected
327+
5. **Performance Testing**: Test performance with realistic data volumes
328+
329+
## Related Sections
330+
331+
<RelatedSection
332+
description="Check out these related resources for more information about adopting OpenFGA."
333+
relatedLinks={[
334+
{
335+
title: 'Custom Roles Step by Step',
336+
description: 'Follow a detailed walkthrough of implementing custom roles.',
337+
link: '../modeling/custom-roles',
338+
},
339+
{
340+
title: 'Multi-tenant RBAC Example',
341+
description: 'See a complete multi-tenant role-based access control implementation.',
342+
link: 'https://github.com/openfga/sample-stores/blob/main/stores/multitenant-rbac',
343+
},
344+
{
345+
title: 'Role Assignments Example',
346+
description: 'Explore a full role assignments implementation.',
347+
link: 'https://github.com/openfga/sample-stores/tree/main/stores/role-assignments',
348+
}
349+
]}
350+
/>

docs/content/best-practices/running-in-production.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,4 @@ By default, both ListObjects and ListUsers have a maximum results limit of 1,000
110110
id: '../modeling/migrating/migrating-relations',
111111
}
112112
]}
113-
/>
113+
/>

docs/content/getting-started/setup-openfga/configure-openfga.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ Experimental feature flags are also not considered part of API compatibility and
368368
OpenFGA telemetry data is collected by default starting on version `v0.3.5`. The telemetry information that is captured includes Metrics, Traces, and Logs.
369369
370370
:::note
371-
Please refer to the [docker-compose.yaml](https://github.com/openfga/openfga/blob/main/docker-compose.yaml) file as an example of how to collect Metrics and Tracing in OpenFGA in a Docker environment using the [OpenTelemetry Collector](https://opentelemetry.io/docs/concepts/data_collection/). This should serve as a good example that you can adjust for your specific deployment scenario.
371+
Please refer to the [docker-compose.yaml](https://github.com/openfga/openfga/blob/main/docker-compose.yaml) file as an example of how to collect Metrics and Tracing in OpenFGA in a Docker environment using the [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/). This should serve as a good example that you can adjust for your specific deployment scenario.
372372
:::
373373
374374
## Metrics

docs/sidebars.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,11 @@ const sidebars = {
406406
label: 'Modeling Best Practices',
407407
id: 'content/best-practices/modeling',
408408
},
409+
{
410+
type: 'doc',
411+
label: 'Modeling Roles',
412+
id: 'content/best-practices/modeling-roles',
413+
},
409414
{
410415
type: 'doc',
411416
label: 'Source of Truth',

0 commit comments

Comments
 (0)