diff --git a/docs/gns3-copilot/roadmap/rbac-user-isolation-roadmap.md b/docs/gns3-copilot/roadmap/rbac-user-isolation-roadmap.md new file mode 100644 index 000000000..ff125faa9 --- /dev/null +++ b/docs/gns3-copilot/roadmap/rbac-user-isolation-roadmap.md @@ -0,0 +1,179 @@ +# RBAC User Isolation Roadmap + +## Overview + +GNS3 3.0 ships with a complete RBAC framework (ACE + Role + Privilege models), but the user isolation layer is incomplete. Users can see resources they should not have access to because: + +- Resource creation does not auto-grant the creator an ACE +- List endpoints return unfiltered results +- Two GET endpoints have RBAC checks bypassed via FIXME + +This document tracks the incremental work to close those gaps. Each phase is independent and deployable. + +## Current State + +| Resource | Route Check | List Filtering | Auto-ACE on Create | ACE Cleanup on Delete | +|---|---|---|---|---| +| Project | `Project.Audit/Modify/Allocate` | Partial — pool isolation exists but non-pool projects leak | **Missing** | Done | +| Template | `Template.Audit` **FIXME** | None — all templates returned | **Missing** | Done | +| Node | `Node.Audit/Modify/Allocate` | N/A (inherits project) | Inherits project | N/A | +| Link | `Link.Audit/Modify/Allocate` | N/A (inherits project) | Inherits project | N/A | +| Drawing | `Drawing.Audit/Modify/Allocate` | N/A (inherits project) | Inherits project | N/A | +| Snapshot | `Snapshot.Audit/Allocate/Restore` | N/A (inherits project) | Inherits project | N/A | +| Image | `Image.Audit/Allocate` | None — all images returned | **Missing** | Missing | +| Compute | `Compute.Audit` **FIXME** | None — all computes returned | N/A (shared infra) | Done | +| Appliance | `Appliance.Audit/Allocate` | None — all appliances returned | N/A (builtin) | N/A | +| Symbol | `Symbol.Audit/Allocate` | None — all symbols returned | N/A (builtin) | N/A | + +## Architecture + +```mermaid +graph TD + subgraph Client + WebUI + CLI + end + + subgraph "Controller API" + Auth[get_current_active_user] + PrivCheck[has_privilege] + Routes[Resource Routes] + AutoACE[auto-ACE on create] + ListFilter[ACE-based list filtering] + end + + subgraph "RBAC Engine" + ACE[(ACE table)] + Role[(Role table)] + Privilege[(Privilege table)] + Checker[check_user_has_privilege] + end + + WebUI --> Auth + CLI --> Auth + Auth --> Routes + Routes --> PrivCheck + Routes --> AutoACE + Routes --> ListFilter + PrivCheck --> Checker + ListFilter --> Checker + Checker --> ACE + Checker --> Role + Role --> Privilege +``` + +## Business Process + +### Project creation with auto-ACE + +```mermaid +sequenceDiagram + actor U as User + participant API as POST /projects + participant Ctrl as Controller + participant ACE as ACE Table + + U->>API: Create project + API->>API: has_privilege("Project.Allocate") + API->>Ctrl: add_project() + Ctrl-->>API: project + API->>ACE: create ACE
(user=creator, role=User,
path=/projects/{id}) + API-->>U: 201 + project +``` + +### Project listing with ACE filtering + +```mermaid +sequenceDiagram + actor U as User + participant API as GET /projects + participant Ctrl as Controller + participant ACE as ACE Table + + U->>API: List projects + API->>API: get_current_active_user (not superadmin) + loop Each project + API->>ACE: check_user_has_privilege(user, path, "Project.Audit") + ACE-->>API: True/False + end + API-->>U: filtered list +``` + +## Phased Plan + +### Phase 1 — MVP: Project isolation + +**Goal**: Users only see projects they created or were granted access to. + +| Task | Files | Detail | +|---|---|---| +| Auto-ACE on project create | `projects.py` — `create_project()` | After `add_project()`, create ACE: user=creator, role=User, path=`/projects/{id}` | +| Fix project list filtering | `projects.py` — `get_projects()` | Remove "sees all non-pool projects" path. Return only projects passing ACE check. | + +**Estimate**: 2 files, ~30 lines changed. + +### Phase 2 — Template isolation + +**Goal**: Users see their own templates + builtin templates only. + +| Task | Files | Detail | +|---|---|---| +| Auto-ACE on template create | `templates.py` — `create_template()` | Same pattern as project | +| Fix template list filtering | `templates.py` — `get_templates()` | Filter by ACE; builtin templates always visible | +| Uncomment `Template.Audit` | `templates.py` lines 75, 167 | Restore `has_privilege("Template.Audit")` | + +**Dependency**: Web UI must handle 403 from `GET /templates/{id}`. Mitigation: keep builtin templates unconditionally visible so the UI always has data. + +### Phase 3 — Image isolation (optional) + +**Goal**: Users see only images they uploaded. + +| Task | Files | +|---|---| +| Auto-ACE on image upload | `images.py` — `upload_image()` | +| Fix image list filtering | `images.py` — `get_images()` | +| ACE cleanup on delete | `images.py` — `delete_image()` | + +### Phase 4 — Default ACE for "Users" group (optional) + +**Goal**: Users in "Users" group can create/list resources without admin ACE intervention. + +| Task | Detail | +|---|---| +| Default ACE on `/projects` | Grant "Users" group → User role → `/projects` (propagate=False) | +| Default ACE on `/templates` | Grant "Users" group → User role → `/templates` (propagate=False) | + +## API Endpoints Changed + +### Phase 1 + +| Method | Path | Change | +|---|---|---| +| `POST` | `/v3/projects` | Auto-create ACE for creator | +| `GET` | `/v3/projects` | Filter by user ACEs | + +### Phase 2 + +| Method | Path | Change | +|---|---|---| +| `POST` | `/v3/templates` | Auto-create ACE for creator | +| `GET` | `/v3/templates` | Filter by user ACEs + builtin | +| `GET` | `/v3/templates/{id}` | Restore `Template.Audit` check | + +## Design Decisions + +1. **Compute stays shared**: Computes are infrastructure, not user-owned. The `Compute.Audit` FIXME stays — all authenticated users see computes. + +2. **No DB migration required**: All phases use the existing ACE/role/privilege tables. No schema changes. + +3. **Performance**: Project list filtering is O(n) — iterates all projects and checks ACE per project. Acceptable for < 500 projects. Can optimize later with direct ACE path queries. + +4. **The FIXME dependency**: `Template.Audit` was commented out because web UI crashes on 403. Fix requires either (a) auto-ACE so users own their templates, or (b) web UI 403 handling. + +## References + +- Discussion: https://github.com/GNS3/gns3-server/discussions/1949 +- RBAC models: `gns3server/db/models/acl.py`, `roles.py`, `privileges.py` +- RBAC repository: `gns3server/db/repositories/rbac.py` +- Auth dependency: `gns3server/api/routes/controller/dependencies/authentication.py` +- RBAC dependency: `gns3server/api/routes/controller/dependencies/rbac.py`