RBAC
Users, groups, roles, and the permission model that gates every dashboard action.
telark models access control as a role-based system on top of custom resources. Users, groups, and roles are first-class CRDs owned by the exporter service; the auth service resolves the permission set for the current session on every request.
The four resources
| Resource | Notes |
|---|---|
User | Identity. Holds id, username, full name, email, identity provider. |
UserPasskey | One per registered authenticator on a user. |
Group | A named collection of users. |
Role | A bundle of scope → permission level rules with optional protection and validity. |
Category | Tagging primitive used to scope roles within a domain. |
Every one of these is persisted as a Kubernetes CRD via the exporter service. The dashboard talks to the same HTTP API the auth service uses internally — no kubectl detour required.
Built-in roles
Four roles ship out of the box and cover the majority of teams:
| Role | What it grants |
|---|---|
Admin | Full read/write on every telark scope, including configuration, RBAC mutation, and global config. |
Contributor | Create and edit protection plans, trigger rollbacks, manage applications. Cannot touch RBAC or global config. |
ReadOnly | Read everything. Cannot mutate anything. |
Owner | Bootstrap admin assigned by the configured email on first login. Same surface as Admin. |
The bootstrap admin is set by the auth-service config; every
additional admin is created by assigning the Admin role via
Settings → Access & permissions.
Custom roles
Custom roles are first-class. The shape:
{
id: string;
name: string;
description: string;
version: string;
type: RoleType;
priority: number;
categoryID: string;
scopesAndPermissions: [{ scope: string; level: PermissionLevel; ... }];
protection?: Protection; // optional system-role guards
status: RoleStatus; // active | deprecated | deleted
validity?: Validity; // optional time-bound role
creationDate: string;
// … audit fields
}A role's scopesAndPermissions is the substantive part — every
entry pairs a telark scope (applications, protection-plans,
global-config, rbac, etc.) with a PermissionLevel.
priority is used to resolve conflicts when a user inherits
multiple roles.
A role's protection block prevents accidental deletion of
system-critical roles. A role's validity block lets a role expire
on a date or after a window — useful for time-bound elevation.
Groups
Groups bundle users. Every user can be a member of multiple groups. A role can be assigned to:
- A specific user (via
assignedTo.userIDs). - A specific group (via
assignedTo.groupIDs).
Permission resolution: take the set of roles assigned directly to
the user, union with the roles assigned to every group the user is
a member of, then sort by priority and resolve conflicts in
priority order. The result is a flat map of scope → PermissionLevel.
Permission levels
A role's scopesAndPermissions uses PermissionLevel to encode
the level of access. The auth-service permissions endpoint
collapses this to a { scope, level, deny? } triple the UI uses
to gate elements.
The dashboard's permission hook
(features/access-and-permissions/hooks/permissions) consumes the
endpoint output and exposes usePermission(scope, level, deny?).
Every button gated by RBAC reads from this hook.
The UI surface
dashboard-ui/src/features/access-and-permissions/ covers:
- Users — list, manage, assign roles directly, scope filters.
- Groups — list, create, edit, attach members, attach roles, bulk operations. (The Create group button is the canonical one — its style is the dashboard's reference for primary buttons.)
- Roles — list, view scopes and permissions, manage category mapping. Custom roles are created from this surface.
- Categories — tags used to filter roles in the role picker.
Every page renders an empty state, a loading state, an error state, and the main list — with permission gating on the create and edit actions.
Endpoints (resource API)
All persistence calls go to the exporter service:
| Method | Path | Purpose |
|---|---|---|
POST | /resources/users | Create a user. |
GET | /resources/users/{id} / ?username= / ?email= | Resolve a user. |
PATCH | /resources/users/{id} | Patch. |
DELETE | /resources/users/{id} | Delete. |
POST | /resources/groups | Create a group. |
GET | /resources/groups/{id} | Read. |
PATCH | /resources/groups/{id} | Patch. |
DELETE | /resources/groups/{id} | Delete. |
POST | /resources/roles | Create a role. |
GET | /resources/roles/{id} | Read. |
PATCH | /resources/roles/{id} | Patch. |
DELETE | /resources/roles/{id} | Delete. |
Every write dispatches an in-app notification so the affected user sees a Role assigned or Group membership changed toast next time they load the dashboard.