Appearance
Role Comparison Matrix
Permissions traced from the portal routes (cyberrange/portal/src/lib/routeRoles.ts, middleware.ts), the API guards (cyberrange/src/provisioning/auth.py, pods_router.py, alerts_endpoint.py, users_router.py, onboarding_router.py, infra_health.py, audit_router.py) and the route classification test (cyberrange/src/provisioning/test_sec01_rbac_matrix.py).
Legend: Yes allowed · No refused · Own only limited to the caller's own data · Not implemented
Portal pages
| Page | Student | Instructor | Admin |
|---|---|---|---|
/dashboard (student dashboard) | Yes | No (redirect to /instructor) | No (redirect to /admin) |
/scenarios, /scenario/[id] (student workspace) | Yes | Yes (no role restriction on these paths) | Yes |
/orientation (first-login orientation) | Yes (student steps) | Yes (instructor steps) | Skipped (redirect to /admin) |
/lab/dvwa/* (DVWA proxy for the caller's own lab) | Own only | Own only | Own only |
/instructor and sub-pages | No (redirect to /dashboard) | Yes | Yes |
/admin and sub-pages | No (redirect to /dashboard) | No (redirect to /instructor) | Yes |
| Sidebar links shown | Dashboard, My Labs | Dashboard, Live labs, Students, Reviews | Dashboard, Users, Pods, System, Audit log, Instructor view |
Student lab pages are open to every role
requiredRolesForPath() only restricts /admin and /instructor, and since pull request 176 redirectPathForRole() also moves staff off /dashboard. Instructors and admins can still open /scenarios and /scenario/[id] directly and start a lab for themselves (every app role may call POST /pods/provision). This is useful for testing, and it is still limited to the caller's own lab.
Labs
| Action | Student | Instructor | Admin | Enforced by |
|---|---|---|---|---|
| Start a lab (one live lab per account) | Own only | Own only | Own only | identity from token; idx_pods_one_active_per_student |
| See lab status | Own only | Own only | Any lab | require_owner_or_admin on GET /pods/{id}/status |
List live labs via GET /pods | Own only | Own only | All | admin branch in list_pods() |
| List all live labs (instructor view, internals hidden) | No | Yes | Yes | require_role(instructor, admin) |
| Open the terminal | Own only | Own only | Any lab (backend only, no UI) | bridge ownership check uses /pods/{id}/status |
DVWA and SIEM links (lab-urls) | Own only | Own only | Own only | require_owner |
| End a lab (destroy) | Own only | Own only | Own only | require_owner |
| Force-destroy any lab (audited) | No | No | Yes | require_role(admin) |
Scoring and progress
| Action | Student | Instructor | Admin | Enforced by |
|---|---|---|---|---|
| Manual Check on a milestone (once per task) | Own lab | Own lab | Own lab | require_owner, lab must be ACTIVE, manual_check_attempts |
| Read milestones and progress | Own only | All students | All students | self-scoped routes; instructor routes |
See where each attempt came from (source: auto, manual, browser, flag, review) | No | Yes | Yes | GET /instructor/students/{id} only |
| Read check-failure reason codes (scoring diagnostics) | No (generic result only) | Yes | Yes | require_role(instructor, admin) on GET /instructor/students/{id}/diagnostics |
| Reset own progress for a scenario ("Try again") | Own only | Own only | Own only | identity from token, audited |
| Submit a flag | Own only | Own only | Own only | identity from token; portal box on flag-only tasks |
| Award a milestone PASS by approving a milestone-scoped review | No | Yes | Yes | resolve_student_review (conflicts, reports and manual reviews) |
| Edit scenarios, milestones or points | Not implemented | Not implemented | Not implemented | static catalog |
SIEM (Wazuh alerts)
| Action | Student | Instructor | Admin |
|---|---|---|---|
| Alerts for own active lab (Scenario 3 viewer) | Own only | Own only | Own only |
| Alerts for any live lab | No | Yes | Yes |
| Lab history and archived alerts for ended labs | No | Yes | Yes |
| Alerts frozen with a submitted report | No | Yes | Yes |
Reviews and evidence
| Action | Student | Instructor | Admin |
|---|---|---|---|
| Submit a report / manual review request | Own | Own | Own |
| Read a review | Own only | Any | Any |
| Resubmit a review returned for retry | Own only | Own only | Own only |
| Upload or delete evidence screenshots | Own reviews | Own reviews | Own reviews |
| View evidence screenshots | Own reviews | Any | Any |
| Review queue, resolve (Approve, Reject, Retry, score, feedback) | No | Yes | Yes |
| Knowledge-gain export, anonymized (JSON/CSV) | No | Yes | Yes |
Knowledge-gain export with real usernames (anonymize=false) or including excluded accounts | No | No (403, audited) | Yes |
| Download one student's progress as CSV (milestones, reviews, live alerts) | No | Yes | Yes |
Administration
| Action | Student | Instructor | Admin |
|---|---|---|---|
| List Keycloak users with their role | No | No | Yes |
| Create a user (single role, temporary password) | No | No | Yes |
| Enable or disable a user | No | No | Yes (not self, not the last admin) |
| Change a user's role | No | No | Yes (not self) |
| Reset a user's password | No | No | Yes (not self) |
| Reset a user's MFA | No | No | Yes (not self) |
| Exclude an account from, or include it in, research reports | No | No | Yes (the API allows any account; the page offers it on other students only) |
| Delete a user | Not implemented | Not implemented | Not implemented |
| System health (API, LXD, Keycloak, Wazuh, capacity, RAM) | No | No | Yes |
| Read the audit log (read-only) and download it as CSV | No | No | Yes |
| Record own orientation as completed | Own only | Own only | Own only (the page skips it) |
Public /health and /capacity | anyone who can reach the API (host-internal) | same | same |
Sources
cyberrange/src/provisioning/test_sec01_rbac_matrix.py classifies every API route as public, any application role, instructor or admin, and fails if a route is added without a classification. The page-level rules come from cyberrange/portal/src/lib/routeRoles.ts and cyberrange/portal/src/lib/navigation.ts.