-
Notifications
You must be signed in to change notification settings - Fork 615
[FEATURE][AUTH]: Add A2A agent RBAC enforcement to token scoping middleware #2389
Description
🔐 Feature: Add A2A Agent RBAC Enforcement to Token Scoping Middleware
Goal
Add A2A agent RBAC enforcement to the token scoping middleware so that A2A agents follow the same visibility model (public/team/private) as other resources, ensuring consistent access control across all entity types.
Why Now?
- Security Gap: A2A agents can be created and accessed without team-based visibility checks, creating an inconsistent security posture
- RBAC Completeness: All other major entities (servers, tools, resources, prompts, gateways) have RBAC enforcement; A2A agents are the missing piece
- Multi-Tenant Requirements: Organizations deploying multi-tenant configurations need A2A agents isolated by team
- Compliance: Audit requirements demand consistent access control across all API resources
📖 User Stories
US-1: Admin - Restrict A2A Agent Access by Team
As a Platform Administrator
I want A2A agents to respect team-based visibility rules
So that agents created by one team are not accessible by other teams
Acceptance Criteria:
Scenario: Team-scoped token accessing team's A2A agent
Given a user with a token scoped to team "engineering"
And an A2A agent "code-reviewer" with visibility "team" belonging to team "engineering"
When the user requests GET /a2a/{agent_id}
Then the request should succeed with status 200
And the agent details should be returned
Scenario: Team-scoped token denied access to other team's agent
Given a user with a token scoped to team "engineering"
And an A2A agent "hr-assistant" with visibility "team" belonging to team "hr"
When the user requests GET /a2a/{agent_id}
Then the request should fail with status 403
And the error should be "Access denied: You do not have permission to access this resource"
Scenario: Public A2A agent accessible by all authenticated users
Given a user with any valid token
And an A2A agent "public-helper" with visibility "public"
When the user requests GET /a2a/{agent_id}
Then the request should succeed with status 200Technical Requirements:
- Add A2A agent pattern to
_RESOURCE_PATTERNSin token_scoping.py - Query
A2AAgent.visibilityandA2AAgent.team_idin_check_resource_team_ownership - Log access decisions for audit trail
US-2: Developer - A2A Agent CRUD Permission Enforcement
As a Developer using the API
I want A2A agent CRUD operations to require appropriate permissions
So that only authorized users can create, update, or delete agents
Acceptance Criteria:
Scenario: Create A2A agent requires agents.create permission
Given a user with a token that has permission "agents.read" only
When the user requests POST /a2a with a new agent payload
Then the request should fail with status 403
And the error should be "Insufficient permissions for this operation"
Scenario: Delete A2A agent requires agents.delete permission
Given a user with a token that has permission "agents.delete"
And an A2A agent the user owns
When the user requests DELETE /a2a/{agent_id}
Then the request should succeed with status 200
Scenario: Update A2A agent requires agents.update permission
Given a user with a token that has permission "agents.update"
And an A2A agent belonging to user's team
When the user requests PUT /a2a/{agent_id}
Then the request should succeed with status 200Technical Requirements:
- Add
AGENTS_CREATE,AGENTS_READ,AGENTS_UPDATE,AGENTS_DELETEtoPermissionsclass - Add A2A permission patterns to
_PERMISSION_PATTERNSin token_scoping.py - Map HTTP methods to required permissions
US-3: Security Auditor - A2A Access Audit Trail
As a Security Auditor
I want all A2A agent access attempts logged
So that I can review who accessed which agents and when
Acceptance Criteria:
Scenario: Successful A2A access is logged
Given audit logging is enabled
When a user successfully accesses an A2A agent
Then a log entry should contain:
| Field | Value |
| resource_type | a2a_agent |
| resource_id | {agent_id} |
| decision | ALLOW |
| user_email | {user_email} |
Scenario: Denied A2A access is logged
Given audit logging is enabled
When a user is denied access to an A2A agent
Then a log entry should contain:
| Field | Value |
| resource_type | a2a_agent |
| decision | DENY |
| reason | team visibility mismatch |🏗 Architecture
Token Scoping Flow for A2A Agents
sequenceDiagram
participant Client
participant Middleware as TokenScopingMiddleware
participant DB as Database
participant API as A2A API
Client->>Middleware: GET /a2a/{agent_id}
Middleware->>Middleware: Extract JWT payload
Middleware->>Middleware: Extract agent_id from path
alt Permission Check
Middleware->>Middleware: Check agents.read in permissions
Note over Middleware: Uses _PERMISSION_PATTERNS
end
alt Visibility Check
Middleware->>DB: SELECT visibility, team_id FROM a2a_agents WHERE id = ?
DB-->>Middleware: {visibility: "team", team_id: "eng-123"}
alt visibility == "public"
Middleware->>API: Allow access
else visibility == "team"
Middleware->>Middleware: Check agent.team_id in token_teams
alt Team match
Middleware->>API: Allow access
else No match
Middleware-->>Client: 403 Forbidden
end
else visibility == "private"
Middleware->>Middleware: Check agent.owner_email == user_email
end
end
API-->>Client: A2A Agent Response
Code Changes
# mcpgateway/db.py - Add to Permissions class
class Permissions:
# ... existing permissions ...
# A2A Agent permissions
AGENTS_CREATE = "agents.create"
AGENTS_READ = "agents.read"
AGENTS_UPDATE = "agents.update"
AGENTS_DELETE = "agents.delete"
AGENTS_INVOKE = "agents.invoke"
# mcpgateway/middleware/token_scoping.py - Add patterns
_RESOURCE_PATTERNS: List[Tuple[Pattern[str], str]] = [
# ... existing patterns ...
(re.compile(r"/a2a/?([a-f0-9\-]+)"), "a2a_agent"),
]
_PERMISSION_PATTERNS: List[Tuple[str, Pattern[str], str]] = [
# ... existing patterns ...
# A2A Agent permissions
("GET", re.compile(r"^/a2a(?:$|/)"), Permissions.AGENTS_READ),
("POST", re.compile(r"^/a2a(?:$|/)"), Permissions.AGENTS_CREATE),
("PUT", re.compile(r"^/a2a/[^/]+(?:$|/)"), Permissions.AGENTS_UPDATE),
("DELETE", re.compile(r"^/a2a/[^/]+(?:$|/)"), Permissions.AGENTS_DELETE),
]📋 Implementation Tasks
Phase 1: Permission Constants
- Add
AGENTS_CREATE,AGENTS_READ,AGENTS_UPDATE,AGENTS_DELETE,AGENTS_INVOKEtoPermissionsclass indb.py - Update
get_all_permissions()to include new agent permissions - Add agent permissions to default roles in
bootstrap_db.py
Phase 2: Token Scoping Patterns
- Add A2A agent pattern
(re.compile(r"/a2a/?([a-f0-9\-]+)"), "a2a_agent")to_RESOURCE_PATTERNS - Add A2A permission patterns to
_PERMISSION_PATTERNSfor GET/POST/PUT/DELETE - Handle
/a2a/{id}/invokeendpoint withAGENTS_INVOKEpermission
Phase 3: Visibility Enforcement
- Add
resource_type == "a2a_agent"branch in_check_resource_team_ownership - Query
A2AAgentmodel for visibility and team_id - Apply public/team/private visibility logic matching other resources
- Handle owner_email check for private visibility
Phase 4: Testing
- Unit tests for A2A pattern extraction from paths
- Unit tests for permission mapping
- Integration tests for team-scoped A2A access
- Integration tests for public A2A access
- Integration tests for permission enforcement on CRUD operations
- Test denied access logging
Phase 5: Documentation
- Update RBAC documentation with A2A agent section
- Document agent permissions in API docs
- Add examples to
todo/rbac.md
⚙️ Configuration Example
No new configuration required. A2A agents use existing visibility field:
{
"name": "Code Review Agent",
"endpoint_url": "https://agent.example.com/v1",
"visibility": "team",
"team_id": "eng-123",
"owner_email": "dev@example.com"
}✅ Success Criteria
- A2A agents with
visibility: teamonly accessible by team members - A2A agents with
visibility: publicaccessible by all authenticated users - A2A agents with
visibility: privateonly accessible by owner - CRUD operations require appropriate
agents.*permissions - All access attempts logged for audit
- No regression in existing RBAC functionality
- Unit test coverage > 90% for new code
- Integration tests pass for all visibility scenarios
🏁 Definition of Done
- Permission constants added to
Permissionsclass - Token scoping patterns added for A2A paths
- Visibility checks implemented in
_check_resource_team_ownership - Unit tests written and passing
- Integration tests written and passing
- Code passes
make verify - RBAC documentation updated
- PR reviewed and approved
🧩 Affected Components
-
mcpgateway/db.py- Permissions class -
mcpgateway/middleware/token_scoping.py- Pattern matching and visibility checks -
mcpgateway/bootstrap_db.py- Default role permissions -
tests/- Unit and integration tests
🔗 Related Issues
- PR fix-2185: fix listing public server #2186 - Added gateway RBAC enforcement (reference implementation)
todo/rbac.md- Documents the visibility model