Skip to content

feat(policy): optional protocol-aware inbound authorization for gateway-less deployments #2144

Description

@zanetworker

Problem Statement

OpenShell can run standalone without an MCP Gateway, Kuadrant, or any external gateway infrastructure. In this deployment model, the supervisor proxy is the only enforcement point for all traffic, inbound and outbound.

When sandbox-to-sandbox communication ships (#1049), sandboxes may exchange A2A protocol messages or MCP JSON-RPC calls directly (peer-to-peer), without a gateway in the path. Issue #2143 covers inbound identity validation (who is calling), but not inbound intent authorization (what the caller is asking to do).

Without protocol-aware inbound policy, the proxy can answer "is Sandbox A allowed to reach Sandbox B?" (network + identity) but not "is Sandbox A allowed to cancel a task on Sandbox B?" (protocol-level operation). In a gateway-based deployment, the gateway handles this. In a standalone deployment, nothing does.

This matters in three scenarios:

1. Standalone enterprise deployments. Customers who deploy OpenShell without an external API gateway still need operation-level access control between sandboxes. Requiring a full gateway stack for protocol-level policy is a high barrier.

2. A2A multi-agent workflows. Agent A delegates a task to Agent B via A2A protocol. B should accept SendMessage and GetTask from A, but not CancelTask or administrative operations. Without protocol parsing, B's proxy sees valid HTTP POST requests from an authorized caller and lets everything through.

3. MCP server sandboxes. A sandbox hosts an MCP server (via ExposeService). Another sandbox calls tools on it. Without protocol parsing, the proxy can't distinguish tools/call for read_file from tools/call for delete_file. Both are POST requests to the same endpoint.

Proposed Design

Add optional protocol-aware inbound authorization to the supervisor proxy. This should be:

  • Opt-in: only active when the sandbox policy specifies protocol-level inbound rules. Default behavior (network + identity only) is unchanged.
  • Protocol-pluggable: start with A2A (JSON-RPC over HTTP, well-defined message types), potentially extend to MCP JSON-RPC.
  • Policy-driven: protocol-level rules are expressed in the sandbox policy YAML alongside existing network rules.

Policy surface

inbound_policy:
  - caller: "spiffe://openshell.local/openshell/sandbox/*"
    protocol: a2a
    allow:
      - SendMessage
      - GetTask
      - SubscribeToTask
    deny:
      - CancelTask

  - caller: "spiffe://openshell.local/openshell/sandbox/agent-admin-*"
    protocol: a2a
    allow: ["*"]  # admin agents can do everything

For MCP (if no MCP Gateway is deployed):

inbound_policy:
  - caller: "spiffe://openshell.local/openshell/sandbox/*"
    protocol: mcp
    allow:
      - tools/call:read_file
      - tools/call:list_directory
    deny:
      - tools/call:delete_file
      - tools/call:write_file

Implementation approach

The L7 layer already parses HTTP method, path, and headers. Protocol-aware parsing adds one more step: for requests matching an inbound_policy with a protocol field, parse the JSON-RPC body to extract the method/operation, then check it against the allow/deny list.

The parsing is lightweight. A2A and MCP both use JSON-RPC 2.0. The method field is at the top level of the JSON body. No deep parsing needed, just serde_json::from_slice to read the method field, then a string match against the policy.

OCSF audit

Protocol-level inbound decisions should produce OCSF events recording: caller SPIFFE ID, protocol detected, operation requested, and disposition (allowed/denied). This extends the inbound auth events from #2143 with operation-level detail.

Alternatives Considered

1. Require a gateway for protocol-level policy. Pro: keeps the proxy simple. Con: forces every multi-agent deployment to run a full gateway stack. Defeats the standalone deployment model. Customers who chose OpenShell for its simplicity now need a full gateway stack (e.g., an API gateway with protocol-aware authorization) to get tool-level access control.

2. Run a separate protocol-aware sidecar alongside the supervisor proxy. Pro: isolates protocol parsing from the sandbox proxy. Con: two proxies intercepting the same traffic. Duplicates network enforcement, credential injection, and traffic interception. Operational complexity for the customer.

3. Always route cross-sandbox traffic through the gateway. Pro: gateway handles all protocol parsing. Con: adds latency (extra hop), gateway is a bottleneck, doesn't work for direct peer connections, and still requires a gateway to be deployed.

4. Build a lightweight protocol parser library as a standalone crate. Pro: single implementation, reusable by any agent platform. Con: additional dependency to maintain. Could work if the interface is narrow (parse JSON-RPC method field, return operation name).

Agent Investigation

From analysis of the current codebase:

  • crates/openshell-sandbox/src/l7/ already contains the L7 inspection layer with mod.rs, relay.rs, token_grant_injection.rs. A protocol parser module (e.g., protocol_parser.rs) would plug in at this layer.
  • crates/openshell-sandbox/src/l7/relay.rs handles HTTP relay for L7 requests. Inbound protocol parsing would hook into the relay path after identity validation (feat(auth): inbound caller authentication and authorization for sandbox-to-sandbox communication #2143) and before forwarding to the agent.
  • Issue MCP endpoints accept JSON-RPC batch payloads #2082 (MCP JSON-RPC batch payloads) already discusses parsing MCP request bodies for policy enforcement. The parsing infrastructure from that issue could be reused for inbound protocol-aware policy.
  • The OPA engine (crates/openshell-sandbox/src/opa/) already receives structured inputs (host, port, binary, method, path). Adding protocol and operation fields to the OPA input would enable Rego-based protocol-level policy without hardcoding allow/deny logic.

Depends on: #2143 (inbound identity validation must exist first)
Related: #1049 (sandbox-to-sandbox communication), #2025 (delegated authority), #2082 (MCP JSON-RPC parsing), #2109 (enterprise permission modes)
Context: This issue covers the standalone/gateway-less case. When a gateway is deployed, protocol-level policy should be handled there instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions