Skip to content

Commit ca97f6a

Browse files
Add rbac explanation
1 parent 1c40a28 commit ca97f6a

File tree

1 file changed

+83
-99
lines changed

1 file changed

+83
-99
lines changed

ee/rbac/README.md

Lines changed: 83 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ erDiagram
7575
}
7676
```
7777

78+
The center of the RBAC system is the subject role bindings table, which assigns a role to a given subject (either a user or a group), and that role has a list of permissions attached to it.
79+
80+
There are two resources to which roles can be assigned: you can have a role within the organization, or you can have a role within the project. If you want to assign a role within the organization, that role has to be of the "organization scope", and if you want to assign a role within the project, then the role you are assigning must be of the "project scope".
81+
7882
### Subject System (Users & Groups)
7983

8084
```mermaid
@@ -110,6 +114,48 @@ erDiagram
110114
}
111115
```
112116

117+
### Additional Complexity
118+
119+
Role Inheritance
120+
121+
One role can inherit another role and all of its permissions. Every time we want to calculate the permissions you have, we have to check the roles you are assigned, but also all the roles they inherit. This is a redundant feature. We're not really using in our production setup (except some Insider roles). Even though this is tested and works, we've never really found a use for it. When you're trying to create a new role within the custom roles UI, there is no way for you to set up role inheritance.
122+
123+
Organization Role to Project Role Mappings
124+
125+
Another table is organization role to project role mappings, which also makes this a bit more complex. This is something we are using regularly. You can say that some organizational role, like "Owner", carries automatic "Admin" access to all of the projects within the organization. In this case, organization role "Owner" maps to project role "Admin", and this also has to be taken into consideration when we are checking if user has access to a project: Even though they might not have a role directly within the project, they maybe have an organization role which maps to project role.
126+
127+
Groups
128+
129+
The subject in subject role bindings can be a user, but it can also be a group. When we are actually trying to see which permissions a user has, we have to track all of the roles assigned directly. We also have to check if the user is part of a group, and then if they are, we also need to check all of the roles that the group has.
130+
We have tested groups thoroughly, but I'm not sure if any customers are using them.
131+
132+
### Key-Value Stores & Audit
133+
134+
```mermaid
135+
erDiagram
136+
user_permissions_key_value_store {
137+
string key
138+
text value
139+
}
140+
141+
project_access_key_value_store {
142+
string key
143+
text value
144+
}
145+
```
146+
147+
User Permission Key Value Store
148+
149+
All of this complexity makes actually figuring out which permissions a user has within an organization (or project) a bit more complex. It's not as simple as just tracking the subject role bindings table. It takes quite a few joins, and some recursive joins. Query which calculates all of the permisions for a given user/organization/project is written in the `Rbac.ComputePermissions` module of rhis service. Depending on the size of the organization, number of user and projects they have, it can take from >1s, to 6,7s to calculate these permission.
150+
151+
That's why we had a need for `user_permissions_key_value_store` and `project_access_key_value_store`. Instead of calculating all of the permissions for every "GET" query, there is one table which stores all of the permissions user has within the org and/or project, and another with list of projects user has access to within the organization.
152+
153+
These key value stores are recalculated anytime somebody is assigned a new role, anytime somebody's role is being removed, when you are joining a group, when you are being removed from a group, or when the role definition changes (which can happen with custom roles).
154+
155+
Performance Issues
156+
157+
As mentioned above, recalculation permissions usually takes around a second, but for some organizations that have a lot of projects, it can take five or six seconds. In some extreme cases, it can take around 10+ seconds, and this is where a problem occurs because we are hitting gRPC request timeout. You get bad UX experience when you want to change a role and you get a spinner for, let's say, 10 seconds, and it just times out. One major improvement we can do is to make role assignment and role retraction asynchronous, like many other operations in RBAC already are.
158+
113159
### Identity Provider Integration
114160

115161
```mermaid
@@ -170,8 +216,44 @@ erDiagram
170216
}
171217
```
172218

219+
### Background Job Tables
220+
221+
```mermaid
222+
erDiagram
223+
collaborator_refresh_requests {
224+
uuid id
225+
uuid org_id
226+
string state
227+
uuid requester_user_id
228+
}
229+
230+
rbac_refresh_project_access_requests {
231+
uuid id
232+
string state
233+
uuid org_id
234+
int user_id
235+
}
236+
237+
rbac_refresh_all_permissions_requests {
238+
int id
239+
string state
240+
int organizations_updated
241+
int retries
242+
}
243+
244+
group_management_request {
245+
int id
246+
string state
247+
uuid user_id
248+
uuid group_id
249+
string action
250+
}
251+
```
252+
173253
### Legacy Tables
174254

255+
These tables are leftover from the old auth system. We still use collaborators table when we want to sych GitHub repo access with the Semaphore project roles.
256+
175257
```mermaid
176258
erDiagram
177259
projects ||--o{ collaborators : ""
@@ -216,102 +298,4 @@ erDiagram
216298
uuid org_id
217299
string name
218300
}
219-
```
220-
221-
### Key-Value Stores & Audit
222-
223-
```mermaid
224-
erDiagram
225-
user_permissions_key_value_store {
226-
string key
227-
text value
228-
}
229-
230-
project_access_key_value_store {
231-
string key
232-
text value
233-
}
234-
235-
global_permissions_audit_log {
236-
int id
237-
string key
238-
text old_value
239-
text new_value
240-
string query_operation
241-
boolean notified
242-
}
243-
```
244-
245-
### Background Job Tables
246-
247-
```mermaid
248-
erDiagram
249-
collaborator_refresh_requests {
250-
uuid id
251-
uuid org_id
252-
string state
253-
uuid requester_user_id
254-
}
255-
256-
rbac_refresh_project_access_requests {
257-
uuid id
258-
string state
259-
uuid org_id
260-
int user_id
261-
}
262-
263-
rbac_refresh_all_permissions_requests {
264-
int id
265-
string state
266-
int organizations_updated
267-
int retries
268-
}
269-
270-
group_management_request {
271-
int id
272-
string state
273-
uuid user_id
274-
uuid group_id
275-
string action
276-
}
277-
```
278-
279-
## Schema Notes
280-
281-
### RBAC Architecture
282-
- **Scopes** categorize permissions (org-level, project-level)
283-
- **Permissions** are individual access rights within scopes
284-
- **Roles** bundle multiple permissions together
285-
- **Role Inheritance** allows roles to inherit permissions from other roles
286-
- **Org-to-Project Mappings** automatically map organization roles to project roles
287-
288-
### Subject System (Polymorphic Design)
289-
- **Subjects** is a base table for both users and groups
290-
- **rbac_users** inherits from subjects (1:1 relationship)
291-
- **groups** inherits from subjects (1:1 relationship)
292-
- **subject_role_bindings** assigns roles to any subject with source tracking
293-
294-
### Binding Sources
295-
The `subject_role_bindings.binding_source` enum tracks where role assignments originate:
296-
- `github` - From GitHub collaborator permissions
297-
- `bitbucket` - From Bitbucket collaborator permissions
298-
- `gitlab` - From GitLab collaborator permissions
299-
- `manually_assigned` - Manually assigned by admin
300-
- `okta` - From Okta/SCIM integration
301-
- `inherited_from_org_role` - Inherited from organization role
302-
- `saml_jit` - From SAML just-in-time provisioning
303-
304-
### Repository Access Mapping
305-
- Maps legacy repository permissions (admin/push/pull) to RBAC roles
306-
- One mapping per organization
307-
- References three different roles for each access level
308-
309-
### Identity Providers
310-
- **OIDC**: OpenID Connect sessions and user mappings
311-
- **Okta**: SAML/SCIM integration with JIT provisioning support
312-
- **SAML JIT**: Just-in-time user provisioning via SAML
313-
314-
### Audit System
315-
- Database trigger on `user_permissions_key_value_store` automatically logs changes
316-
- Tracks old/new values for permission changes
317-
- Notified flag for tracking alert status
301+
```

0 commit comments

Comments
 (0)