feat(auth): inbound caller authentication and authorization for sandbox-to-sandbox communication
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 8.7k
- Forks
- 1.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 253
Description
Problem Statement
When sandbox-to-sandbox communication ships (#1049), the receiving sandbox needs to verify the identity of the calling sandbox and authorize the request. Today, sandbox supervisors only accept traffic from two sources: the gateway (via the relay stream, authenticated by the gateway's own identity) and the agent process inside the sandbox (via loopback). There is no mechanism for a sandbox to authenticate or authorize an inbound request from another sandbox or external caller.
This gap becomes critical in three scenarios:
1. Multi-agent workflows (#1049): Sandbox A delegates a task to Sandbox B. Sandbox B needs to verify that A is who it claims to be (identity) and that A is allowed to call B (authorization). Without this, any sandbox that can reach B's network endpoint can invoke it.
2. Exposed services: When a sandbox exposes a service via ExposeService RPC, external callers (webhooks, CI systems, other cluster workloads) can reach it. The supervisor accepts these connections without validating the caller's identity.
3. Delegated authority (#2025): When a parent agent spawns a child agent with narrower authority, the child's sandbox needs to verify that inbound instructions come from the authorized parent, not from an unrelated sandbox that discovered the child's endpoint.
Without inbound authentication, cross-sandbox communication is a lateral movement vector: a compromised sandbox can call any other sandbox that exposes a service, with no identity proof required.
Proposed Design
The supervisor's inbound path should validate caller identity using SPIFFE, consistent with how outbound identity already works (PR #1784).
Inbound authentication (identity)
When a request arrives at a sandbox from another sandbox or external caller, the supervisor validates the caller's SPIFFE JWT-SVID (or gateway-minted JWT) via the authenticator chain. The result is a Principal identifying the caller. Requests without a valid token are rejected.
For cross-sandbox traffic, both sandboxes present SPIFFE JWT-SVIDs. The receiving sandbox validates the caller's SVID via its own SPIRE Workload API socket (both share the same trust domain). The SPIFFE ID identifies which sandbox is calling.
Inbound authorization (policy)
The sandbox policy defines which callers are allowed. Options include:
- SPIFFE ID allowlist:
allow_callers: [spiffe://openshell.local/openshell/sandbox/<uuid>] - Topology-based: the gateway provides a caller allowlist derived from the sandbox's policy or the topology CRD (#1049)
- Gateway-brokered: all cross-sandbox traffic routes through the gateway, which performs the authorization check using its knowledge of both sandboxes' policies
Audit
Every inbound request should produce an OCSF event recording: caller SPIFFE ID, target sandbox, method called, and disposition (allowed/denied). This is essential for the delegation audit trail required by #2025.
Alternatives Considered
1. Gateway-only mediation: All cross-sandbox traffic routes through the gateway. The gateway authenticates both sides and authorizes the call. Pro: no changes to the supervisor. Con: adds latency (extra hop through gateway), gateway becomes a bottleneck for sandbox-to-sandbox traffic, doesn't work for direct peer connections.
2. Network policy only: Use Kubernetes NetworkPolicy to control which sandboxes can reach each other. Pro: no code changes. Con: network-level only (no identity verification, no per-method authorization, no audit trail). A sandbox that can reach another sandbox's IP can send any request.
3. mTLS between sandboxes: Each sandbox uses its SPIFFE X.509 SVID for mutual TLS to peer sandboxes. Pro: strong transport-level identity. Con: requires TLS termination at the supervisor for inbound traffic, more complex than JWT validation on gRPC metadata. Could complement JWT-SVID validation as defense in depth.
Agent Investigation
From analysis of the current codebase:
crates/openshell-server/src/auth/principal.rsdefinesPrincipal::Sandboxwhich could be extended withcaller_sandbox_idfor cross-sandbox context- The authenticator chain (
crates/openshell-server/src/multiplex.rs) already supports SPIFFE validation; the same logic could be reused in the supervisor crates/openshell-sandbox/src/grpc_client.rshandles outbound auth; an equivalent inbound path would validate tokens on incoming relay or service requests- PR #1784's
spiffe_endpoint.rsprovides the SPIFFE Workload API client that the supervisor would use for inbound SVID validation - OCSF builders in
crates/openshell-ocsf/already cover network activity and SSH authentication events; an inbound auth event type would follow the same pattern
Depends on: #1049 (sandbox-to-sandbox communication path)
Related: #2025 (delegated authority policy), #1056 (offline flow verification), #981 (split-pod model)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading crates/openshell-server/src/auth/principal.rs and multiplex.rs, then inspect crates/openshell-sandbox/src/grpc_client.rs and PR #1784's spiffe_endpoint.rs. Determine which inbound path depends on #1049 and resolve the proposed authentication, authorization, and OCSF audit approach before implementation. Done means inbound callers are validated, authorized by the selected policy, and recorded as allowed or denied.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- grpc, rust
- Domain
- authentication, authorization, distributed-systems, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100