RBAC Redesign Proposal
This document outlines the proposed improvements to Clue2App's Role-Based Access Control system.
Current Issues
| Issue | Severity | Impact |
|---|---|---|
| No server-side permission checks | Critical | Security vulnerability |
| Hardcoded permissions in frontend | High | Can't update without deploy |
| Groups = Roles (conflated) | Medium | Inflexible permission model |
| No resource-level permissions | Medium | All-or-nothing access |
| No audit logging | Medium | No accountability |
Proposed Architecture
New Data Model
Permission Code Format
Use a hierarchical permission code system:
{resource}:{action}
Examples:
- apps:create
- apps:read
- apps:update
- apps:delete
- apps:deploy
- apps:logs:read
- projects:create
- projects:members:add
- users:create
- users:password:reset
- groups:create
- roles:assign
Proposed Roles
System Roles (Platform-Wide)
| Role | Permissions | Scope |
|---|---|---|
PLATFORM_ADMIN | All permissions | Global |
PLATFORM_SUPPORT | Read all, limited write | Global |
Account Roles (Account-Wide)
| Role | Permissions |
|---|---|
ACCOUNT_OWNER | Full account control |
ACCOUNT_ADMIN | Manage users, groups, projects |
BILLING_ADMIN | Manage billing only |
Project Roles (Project-Scoped)
| Role | Permissions |
|---|---|
PROJECT_ADMIN | Full project control |
PROJECT_DEVELOPER | Create/edit apps, view logs |
PROJECT_VIEWER | Read-only access |
PROJECT_DEPLOYER | Deploy only (for CI/CD) |
Permission Hierarchy
PLATFORM_ADMIN
└── ACCOUNT_OWNER
└── ACCOUNT_ADMIN
└── PROJECT_ADMIN
├── PROJECT_DEVELOPER
│ └── PROJECT_VIEWER
└── PROJECT_DEPLOYER
Implementation Plan
Phase 1: Backend Permission Middleware
Add server-side permission validation to all protected APIs.
New Middleware:
# Pseudo-code for permission middleware
@require_permission("apps:create")
def create_app(request):
# Only executes if user has apps:create permission
pass
@require_permission("apps:read", resource_param="app_id")
def get_app(request, app_id):
# Checks if user has apps:read on this specific app
pass
API Changes:
| Endpoint | Required Permission |
|---|---|
POST /apps | apps:create |
GET /apps | apps:read |
PUT /apps/{id} | apps:update + resource check |
DELETE /apps/{id} | apps:delete + resource check |
POST /apps/{id}/deploy | apps:deploy + resource check |
GET /apps/{id}/logs | apps:logs:read + resource check |
Phase 2: Dynamic Permission Loading
Move permissions from frontend constants to backend API.
New Endpoints:
GET /api/permissions
→ Returns list of all permissions with metadata
GET /api/roles
→ Returns list of roles with their permissions
GET /api/users/me/permissions
→ Returns current user's effective permissions
Frontend Changes:
// Before (hardcoded)
const ROLE_PERMISSIONS = { ACCOUNT_ADMIN: [...] };
// After (dynamic)
const { permissions } = await api.get('/users/me/permissions');
const canCreateApp = permissions.includes('apps:create');
Phase 3: Resource-Level Permissions
Enable granting permissions on specific resources.
New Table: resource_permissions
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key |
| user_id | uuid | User granted permission |
| group_id | uuid | Or group granted permission |
| permission_id | uuid | The permission |
| resource_type | string | APP, PROJECT, etc. |
| resource_id | uuid | Specific resource |
| granted_by | uuid | Who granted it |
| expires_at | timestamp | Optional expiration |
Example Usage:
Grant "alice" the "apps:deploy" permission on app "my-api":
INSERT INTO resource_permissions
(user_id, permission_id, resource_type, resource_id)
VALUES
('alice-uuid', 'apps-deploy-uuid', 'APP', 'my-api-uuid');
Phase 4: Audit Logging
Track all permission-related changes.
Audit Events:
| Event | Data Captured |
|---|---|
user.created | user details, created_by |
user.updated | changed fields, old/new values |
user.deleted | user details, deleted_by |
group.member.added | user, group, added_by |
group.member.removed | user, group, removed_by |
role.assigned | user/group, role, assigned_by |
permission.granted | subject, permission, resource, granted_by |
permission.revoked | subject, permission, resource, revoked_by |
Audit API:
GET /api/audit/users/{userId}
→ Returns audit log for specific user
GET /api/audit/resources/{type}/{id}
→ Returns audit log for specific resource
GET /api/audit?action=permission.granted&since=2024-01-01
→ Search audit logs with filters
Phase 5: Custom Roles
Allow accounts to create their own roles.
UI Flow:
- Account Admin goes to Settings → Roles
- Clicks "Create Custom Role"
- Names the role (e.g., "QA Engineer")
- Selects permissions from checklist
- Optionally inherits from existing role
- Saves → Role available for assignment
Constraints:
- Custom roles scoped to account
- Cannot exceed creator's permissions
- Can inherit from standard roles
- Audit logged
API Design
Permission Check Endpoint
POST /api/permissions/check
{
"permission": "apps:deploy",
"resource_type": "APP",
"resource_id": "uuid-of-app"
}
Response:
{
"allowed": true,
"reason": "User has PROJECT_DEVELOPER role on project containing this app"
}
Effective Permissions Endpoint
GET /api/users/me/permissions?resource_type=APP&resource_id=uuid
Response:
{
"permissions": [
"apps:read",
"apps:update",
"apps:logs:read"
],
"roles": [
{
"name": "PROJECT_DEVELOPER",
"scope": "project",
"project_id": "uuid"
}
]
}
Migration Strategy
Step 1: Add New Tables (Non-Breaking)
- Create new permission, role_permission, resource_permission, audit_log tables
- Keep existing tables intact
Step 2: Dual-Write Period
- Write to both old and new systems
- Read from old system
- Validate consistency
Step 3: Switch Reads
- Read from new system
- Write to both systems
- Monitor for issues
Step 4: Deprecate Old System
- Stop writing to old tables
- Remove old permission checks from frontend
- Clean up old tables
Security Considerations
Token Scope
- Include permission claims in JWT
- Short-lived access tokens (15 min)
- Refresh tokens for session extension
Rate Limiting
- Permission check endpoints: 1000/min
- Audit log queries: 100/min
- Role modifications: 10/min
Sensitive Operations
- Role assignment requires MFA
- Custom role creation requires account owner
- Bulk permission changes require approval
Success Metrics
| Metric | Target |
|---|---|
| Permission check latency | < 10ms |
| Unauthorized access attempts blocked | 100% |
| Audit log coverage | 100% of permission changes |
| Custom role adoption | 20% of accounts |
Timeline
| Phase | Duration | Dependencies |
|---|---|---|
| Phase 1: Backend Middleware | 2 weeks | None |
| Phase 2: Dynamic Permissions | 1 week | Phase 1 |
| Phase 3: Resource Permissions | 2 weeks | Phase 2 |
| Phase 4: Audit Logging | 1 week | Phase 1 |
| Phase 5: Custom Roles | 2 weeks | Phase 2, 3 |
Total: ~8 weeks
Appendix: Permission Codes
Application Permissions
apps:create- Create new applicationsapps:read- View application detailsapps:update- Modify application settingsapps:delete- Delete applicationsapps:deploy- Trigger deploymentsapps:logs:read- View application logsapps:logs:stream- Stream live logsapps:env:read- View environment variablesapps:env:write- Modify environment variablesapps:secrets:read- View secrets (masked)apps:secrets:write- Modify secrets
Project Permissions
projects:create- Create new projectsprojects:read- View project detailsprojects:update- Modify project settingsprojects:delete- Delete projectsprojects:members:read- View project membersprojects:members:add- Add members to projectprojects:members:remove- Remove members from project
User Management Permissions
users:create- Create users in accountusers:read- View user detailsusers:update- Modify user detailsusers:delete- Delete usersusers:password:reset- Reset user passwordsusers:impersonate- Impersonate users (admin only)
Group Permissions
groups:create- Create groupsgroups:read- View group detailsgroups:update- Modify groupsgroups:delete- Delete groupsgroups:members:add- Add users to groupsgroups:members:remove- Remove users from groups
Role Permissions
roles:read- View available rolesroles:create- Create custom rolesroles:update- Modify custom rolesroles:delete- Delete custom rolesroles:assign- Assign roles to users/groups