Skip to main content

RBAC Redesign Proposal

This document outlines the proposed improvements to Clue2App's Role-Based Access Control system.

Current Issues

IssueSeverityImpact
No server-side permission checksCriticalSecurity vulnerability
Hardcoded permissions in frontendHighCan't update without deploy
Groups = Roles (conflated)MediumInflexible permission model
No resource-level permissionsMediumAll-or-nothing access
No audit loggingMediumNo 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)

RolePermissionsScope
PLATFORM_ADMINAll permissionsGlobal
PLATFORM_SUPPORTRead all, limited writeGlobal

Account Roles (Account-Wide)

RolePermissions
ACCOUNT_OWNERFull account control
ACCOUNT_ADMINManage users, groups, projects
BILLING_ADMINManage billing only

Project Roles (Project-Scoped)

RolePermissions
PROJECT_ADMINFull project control
PROJECT_DEVELOPERCreate/edit apps, view logs
PROJECT_VIEWERRead-only access
PROJECT_DEPLOYERDeploy 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:

EndpointRequired Permission
POST /appsapps:create
GET /appsapps:read
PUT /apps/{id}apps:update + resource check
DELETE /apps/{id}apps:delete + resource check
POST /apps/{id}/deployapps:deploy + resource check
GET /apps/{id}/logsapps: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

ColumnTypeDescription
iduuidPrimary key
user_iduuidUser granted permission
group_iduuidOr group granted permission
permission_iduuidThe permission
resource_typestringAPP, PROJECT, etc.
resource_iduuidSpecific resource
granted_byuuidWho granted it
expires_attimestampOptional 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:

EventData Captured
user.createduser details, created_by
user.updatedchanged fields, old/new values
user.deleteduser details, deleted_by
group.member.addeduser, group, added_by
group.member.removeduser, group, removed_by
role.assigneduser/group, role, assigned_by
permission.grantedsubject, permission, resource, granted_by
permission.revokedsubject, 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:

  1. Account Admin goes to Settings → Roles
  2. Clicks "Create Custom Role"
  3. Names the role (e.g., "QA Engineer")
  4. Selects permissions from checklist
  5. Optionally inherits from existing role
  6. 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

MetricTarget
Permission check latency< 10ms
Unauthorized access attempts blocked100%
Audit log coverage100% of permission changes
Custom role adoption20% of accounts

Timeline

PhaseDurationDependencies
Phase 1: Backend Middleware2 weeksNone
Phase 2: Dynamic Permissions1 weekPhase 1
Phase 3: Resource Permissions2 weeksPhase 2
Phase 4: Audit Logging1 weekPhase 1
Phase 5: Custom Roles2 weeksPhase 2, 3

Total: ~8 weeks


Appendix: Permission Codes

Application Permissions

  • apps:create - Create new applications
  • apps:read - View application details
  • apps:update - Modify application settings
  • apps:delete - Delete applications
  • apps:deploy - Trigger deployments
  • apps:logs:read - View application logs
  • apps:logs:stream - Stream live logs
  • apps:env:read - View environment variables
  • apps:env:write - Modify environment variables
  • apps:secrets:read - View secrets (masked)
  • apps:secrets:write - Modify secrets

Project Permissions

  • projects:create - Create new projects
  • projects:read - View project details
  • projects:update - Modify project settings
  • projects:delete - Delete projects
  • projects:members:read - View project members
  • projects:members:add - Add members to project
  • projects:members:remove - Remove members from project

User Management Permissions

  • users:create - Create users in account
  • users:read - View user details
  • users:update - Modify user details
  • users:delete - Delete users
  • users:password:reset - Reset user passwords
  • users:impersonate - Impersonate users (admin only)

Group Permissions

  • groups:create - Create groups
  • groups:read - View group details
  • groups:update - Modify groups
  • groups:delete - Delete groups
  • groups:members:add - Add users to groups
  • groups:members:remove - Remove users from groups

Role Permissions

  • roles:read - View available roles
  • roles:create - Create custom roles
  • roles:update - Modify custom roles
  • roles:delete - Delete custom roles
  • roles:assign - Assign roles to users/groups