-
Notifications
You must be signed in to change notification settings - Fork 574
Labels
SHOULDP2: Important but not vital; high-value items that are not crucial for the immediate releaseP2: Important but not vital; high-value items that are not crucial for the immediate releasedatabaseenhancementNew feature or requestNew feature or requestpythonPython / backend development (FastAPI)Python / backend development (FastAPI)securityImproves securityImproves securitysweng-group-5Group 5 - Policy-as-Code Security & Compliance AutomationGroup 5 - Policy-as-Code Security & Compliance AutomationtcdSwEng ProjectsSwEng Projects
Milestone
Description
Summary
Implement a centralized, configurable RBAC/ABAC policy engine that consolidates all access control decisions into a single, admin-configurable system. Currently, access control is scattered across multiple layers with hardcoded permissions, making it difficult to customize without code changes.
Current State Analysis
Access Control Decision Points (Scattered)
┌─────────────────────────────────────────────────────────────────────────────────┐
│ CURRENT: Scattered Access Control │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Token │ │ RBAC │ │ Service │ │ Route │ │
│ │ Scoping │ │ Middleware │ │ Layer │ │ Handler │ │
│ │ Middleware │ │ Decorator │ │ Filtering │ │ Logic │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ • Team membership • Role perms • Visibility • is_admin check │
│ • IP restrictions • Admin bypass • Owner check • Custom logic │
│ • Time windows • Plugin hooks • Team filter • Hardcoded rules │
│ • Server scoping • Audit log • Query mods │
│ │
│ PROBLEMS: Inconsistent enforcement, no single source of truth, │
│ hardcoded permissions, difficult to audit/configure │
└─────────────────────────────────────────────────────────────────────────────────┘
What's Currently Hardcoded
| Component | Hardcoded Elements | Location |
|---|---|---|
| Permissions | tools.read, resources.create, etc. |
mcpgateway/db.py |
| Role scopes | global, team, personal |
mcpgateway/db.py |
| Visibility levels | public, team, private |
Multiple files |
| Time restrictions | 9-17 UTC, Mon-Fri | token_scoping.py |
| Admin bypass | is_admin=True check |
Multiple middlewares |
| Team roles | owner, member |
EmailTeamMember.role |
Current Enforcement Layers
-
TokenScopingMiddleware (
middleware/token_scoping.py)- Team membership validation
- Resource visibility filtering
- Server-specific scoping
- IP/CIDR restrictions
- Time-based restrictions
- Token-level permissions
-
RBAC Decorators (
middleware/rbac.py)@require_permission()on routes- Role-based permission checks
- Plugin hook integration
- Admin bypass logic
-
Service Layer (
services/*_service.py)- Visibility filtering in queries
- Owner-based access checks
- Team membership filtering
-
Route Handlers (
main.py,admin.py)- Ad-hoc
is_adminchecks - Custom authorization logic
- Ad-hoc
Proposed Solution: Unified Policy Engine
Architecture Overview
┌─────────────────────────────────────────────────────────────────────────────────┐
│ PROPOSED: Centralized Policy Engine │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ │
│ │ Policy Engine │ │
│ │ (Single Source │ │
│ │ of Truth) │ │
│ └──────────┬──────────┘ │
│ │ │
│ ┌──────────────────────┼──────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Policy Store │ │ Policy Cache │ │ Audit Logger │ │
│ │ (Database) │ │ (Redis/Memory) │ │ (All Decisions)│ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Policy Definitions │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ • Permissions (configurable, not hardcoded) │ │
│ │ • Roles (with inheritance chains) │ │
│ │ • Policies (ABAC rules with conditions) │ │
│ │ • Resource rules (per-resource permissions) │ │
│ │ • Time/IP/context constraints │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Policy Definition Schema
# Example: policies.yaml (or database-stored)
permissions:
- name: tools.read
description: "Read tool definitions"
resource_type: tool
action: read
- name: tools.execute
description: "Execute tools"
resource_type: tool
action: execute
# Can add custom permissions without code changes
roles:
- name: viewer
scope: global
permissions:
- tools.read
- resources.read
- prompts.read
- name: developer
scope: team
inherits: viewer
permissions:
- tools.execute
- resources.create
- name: admin
scope: global
permissions: ["*"]
policies:
# ABAC-style policies
- name: team-resource-access
description: "Team members can access team resources"
effect: allow
conditions:
- resource.visibility == "team"
- resource.team_id IN subject.teams
- name: owner-full-access
description: "Resource owners have full access"
effect: allow
conditions:
- resource.owner_email == subject.email
- name: business-hours-only
description: "Restrict to business hours"
effect: deny
conditions:
- context.hour < 9 OR context.hour > 17
- subject.has_tag("restricted-hours")
- name: ip-allowlist
description: "IP-based access control"
effect: allow
conditions:
- context.ip IN policy.allowed_cidrs
resource_rules:
# Fine-grained per-resource permissions
- resource_type: tool
resource_id: "sensitive-tool-123"
allowed_roles: [admin, security-team]
denied_users: [contractor@example.com]Policy Engine Interface
class PolicyEngine:
"""Centralized access control decision point."""
async def check_access(
self,
subject: Subject, # User/token info
action: str, # e.g., "read", "execute"
resource: Resource, # Resource being accessed
context: Context # Request context (IP, time, etc.)
) -> AccessDecision:
"""
Single entry point for ALL access control decisions.
Returns:
AccessDecision with:
- allowed: bool
- reason: str
- matching_policies: List[str]
- audit_id: str
"""
async def get_accessible_resources(
self,
subject: Subject,
resource_type: str,
action: str,
context: Context
) -> ResourceFilter:
"""
Returns filter criteria for list queries.
Used by services to filter results efficiently.
"""
async def explain_access(
self,
subject: Subject,
action: str,
resource: Resource,
context: Context
) -> AccessExplanation:
"""
Debug tool: explains why access was granted/denied.
Shows all evaluated policies and their results.
"""Admin UI for Policy Management
┌─────────────────────────────────────────────────────────────────┐
│ Admin UI → Access Control │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │ Permissions │ │ Roles │ │ Policies │ │ Audit │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └───────────┘ │
│ │
│ Permissions: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ [+] Add Permission │ │
│ │ │ │
│ │ ☑ tools.read - Read tool definitions [Edit][Del]│ │
│ │ ☑ tools.execute - Execute tools [Edit][Del]│ │
│ │ ☑ tools.create - Create new tools [Edit][Del]│ │
│ │ ☐ tools.admin - Full tool management [Edit][Del]│ │
│ │ ... │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Policies: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ [+] Add Policy │ │
│ │ │ │
│ │ ● team-resource-access [Active] [Edit] [Test] │ │
│ │ IF resource.visibility = "team" │ │
│ │ AND resource.team_id IN subject.teams │ │
│ │ THEN ALLOW │ │
│ │ │ │
│ │ ● business-hours-only [Active] [Edit] [Test] │ │
│ │ IF context.hour < 9 OR context.hour > 17 │ │
│ │ AND subject.has_restriction("business-hours") │ │
│ │ THEN DENY with "Outside business hours" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Policy Tester: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Subject: [user@example.com ▼] │ │
│ │ Action: [execute ▼] │ │
│ │ Resource:[tool:abc-123 ▼] │ │
│ │ │ │
│ │ [Test Access] │ │
│ │ │ │
│ │ Result: ✅ ALLOWED │ │
│ │ Matching policies: │ │
│ │ • team-resource-access (user in team "developers") │ │
│ │ • role:developer has permission tools.execute │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Implementation Phases
Phase 1: Foundation (Core Engine)
- Create
PolicyEngineservice with unifiedcheck_access()interface - Database models for configurable permissions, policies
- Migration from hardcoded
Permissionsclass to database - Consolidate all middleware checks to use
PolicyEngine - Comprehensive audit logging for all decisions
Phase 2: ABAC Support
- Policy condition expression language (simple DSL or JSON)
- Context attributes (time, IP, request metadata)
- Resource attributes (visibility, team, owner, tags)
- Subject attributes (roles, teams, custom attributes)
- Policy evaluation with AND/OR/NOT combinations
Phase 3: Admin UI
- Permission management UI (CRUD)
- Role management with inheritance visualization
- Policy editor with syntax validation
- Policy tester/simulator
- Access decision audit viewer
Phase 4: Advanced Features
- Fine-grained resource-level permissions
- Policy versioning and rollback
- Policy import/export (YAML/JSON)
- External policy engine integration (OPA/Cedar)
- SSO group → team/role mapping
- Delegation and temporary access grants
Benefits
| Current State | Proposed State |
|---|---|
| Hardcoded permissions require code changes | Admin-configurable permissions |
| Scattered enforcement across 4+ layers | Single PolicyEngine entry point |
| No ABAC support | Full ABAC with conditions |
| Limited audit trail | Comprehensive decision logging |
| No policy testing | Built-in policy simulator |
| Token scoping separate from RBAC | Unified access control model |
| Admin bypass is all-or-nothing | Granular admin permissions |
Database Schema Changes
-- New tables for configurable RBAC
CREATE TABLE access_permissions (
id UUID PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
resource_type VARCHAR(50),
action VARCHAR(50),
is_system BOOLEAN DEFAULT FALSE,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
CREATE TABLE access_policies (
id UUID PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
effect VARCHAR(10) NOT NULL, -- 'allow' or 'deny'
priority INTEGER DEFAULT 0,
conditions JSONB NOT NULL, -- Policy conditions
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP,
updated_at TIMESTAMP,
created_by VARCHAR(255)
);
CREATE TABLE access_decisions (
id UUID PRIMARY KEY,
timestamp TIMESTAMP NOT NULL,
subject_email VARCHAR(255),
subject_type VARCHAR(50), -- 'user', 'token', 'service'
action VARCHAR(50),
resource_type VARCHAR(50),
resource_id VARCHAR(255),
decision VARCHAR(10), -- 'allow', 'deny'
reason TEXT,
matching_policies JSONB,
context JSONB, -- IP, time, etc.
request_id VARCHAR(100)
);
CREATE TABLE resource_access_rules (
id UUID PRIMARY KEY,
resource_type VARCHAR(50) NOT NULL,
resource_id VARCHAR(255), -- NULL = all resources of type
policy_id UUID REFERENCES access_policies(id),
allowed_roles JSONB,
denied_users JSONB,
is_active BOOLEAN DEFAULT TRUE
);API Endpoints
# Policy Management
GET /admin/access/permissions # List all permissions
POST /admin/access/permissions # Create permission
PUT /admin/access/permissions/{id} # Update permission
DELETE /admin/access/permissions/{id} # Delete permission
GET /admin/access/policies # List all policies
POST /admin/access/policies # Create policy
PUT /admin/access/policies/{id} # Update policy
DELETE /admin/access/policies/{id} # Delete policy
# Policy Testing
POST /admin/access/test # Test access decision
GET /admin/access/explain # Explain access for user/resource
# Audit
GET /admin/access/audit # Query access decisions
GET /admin/access/audit/{id} # Get decision details
# Export/Import
GET /admin/access/export # Export all policies
POST /admin/access/import # Import policies
Related Issues
- [BUG]: SSE and /mcp list paths ignore visibility filters #1915 - MCP list operations respect token team scope
- [BUG]: REST /tools list endpoint returns stale visibility data after tool update #2018 - REST /tools list endpoint cache invalidation
References
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
SHOULDP2: Important but not vital; high-value items that are not crucial for the immediate releaseP2: Important but not vital; high-value items that are not crucial for the immediate releasedatabaseenhancementNew feature or requestNew feature or requestpythonPython / backend development (FastAPI)Python / backend development (FastAPI)securityImproves securityImproves securitysweng-group-5Group 5 - Policy-as-Code Security & Compliance AutomationGroup 5 - Policy-as-Code Security & Compliance AutomationtcdSwEng ProjectsSwEng Projects