Repository navigation
feat(policy): optional protocol-aware inbound authorization for gateway-less deployments #2144
Description
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 everythingFor 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_fileImplementation 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 withmod.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.rshandles 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). Addingprotocolandoperationfields 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.
Activity
rpelevin commentedon Jul 6, 2026
This is the boundary I would make conformance-visible for the gateway-less case.
The useful test is not only that the proxy can parse the JSON-RPC method before forwarding. It is that the proxy emits a stable inbound authorization decision record for every terminal path.
The record I would want bound before forward is small:
Then the negative cases become crisp:
That keeps the feature optional and lightweight while making standalone deployments auditable: identity answers who may connect, protocol policy answers what operation may cross the boundary, and the terminal record proves whether anything was forwarded.
TaylorMutch commentedon Jul 10, 2026
github-actions commentedon Jul 26, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.
rpelevin commentedon Jul 28, 2026
This remains relevant to the policy-aware inbound authorization boundary we have been tracking. The stale marker may close the issue soon. If the maintainers still consider this an active design question, the narrow seam we are watching is how a gateway-less deployment binds inbound protocol/profile authorization to the exact caller, policy, and resulting evidence. If it is no longer active, no action needed.
zanetworker commentedon Jul 29, 2026
How to "unstale" an issue in this case :)?
github-actions commentedon Sep 12, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.