Skip to main content

OpenShell Integration with Rossoctl

Status: PoC validated (PR #1300) — MVP in progress (epic #1363) Source: NVIDIA/OpenShell (Apache 2.0) Design doc: openshell-mvp.md (gateway-per-tenant architecture)


1. Overview

OpenShell is a sandbox runtime for autonomous AI agents providing kernel-level isolation (Landlock, seccomp, network namespaces) with OPA/Rego policy enforcement and zero-secret credential isolation. Rossoctl integrates OpenShell to provide agent process isolation alongside its existing platform services (identity, budget, observability).

2. Current PoC Architecture

The PoC deploys OpenShell (upstream, with K8s compute driver) alongside Rossoctl Operator. No UI or Backend API — E2E tests call agents directly via A2A.

Components

ComponentNamespacePurpose
OpenShell Gatewayopenshell-systemSandbox control plane
K8s Compute Driveropenshell-systemCreates sandbox pods via K8s API
Rossoctl Operatorrossoctl-systemAgentRuntime CRs, webhook injection
KeycloakkeycloakOIDC provider
SPIREspire-systemWorkload identity (SPIFFE)
Istio Ambientistio-systemmTLS mesh
LiteLLMrossoctl-systemLLM model routing
Budget Proxyteam1LLM token budget enforcement
PostgreSQLteam1Sessions + budget databases

2b. MVP Target Architecture

Epic: #1363 — Gateway-per-Tenant on Kind + OpenShift Design doc: PR #1364

The MVP replaces the single shared gateway with gateway-per-tenant isolation, adds OIDC authentication via Keycloak, cert-manager TLS, session persistence (dtach), and headless agent execution (AgentTask CRD).

Cluster
├── keycloak/ Shared OIDC provider (realm: openshell)
├── agent-sandbox-system/ Shared CRD controller
├── team1/ Tenant 1: gateway + driver + sandboxes
│ ├── gateway (StatefulSet) Forked openshell-server + OIDC (PR #935)
│ ├── compute-driver (sidecar) Forked openshell-driver-openshift (Go)
│ ├── credentials-driver openshell-credentials-keycloak (Go, new)
│ ├── Service + Ingress TCPRoute (Kind) or Route (OpenShift)
│ └── sandbox pods Created by agent-sandbox-controller
└── team2/ Tenant 2: same structure, fully isolated

PoC → MVP Transition

PoC (PR #1300)MVP (#1363)Issue
Single gateway in openshell-systemGateway-per-tenant#1358
--disable-tls --disable-gateway-authcert-manager TLS + Keycloak OIDC#1357
Kustomize manifestscharts/openshell/ Helm chart#1358
Monolithic fulltest scriptLayered scripts (build, deploy-shared, deploy-tenant)#1361
In-process K8s compute driverOut-of-process Go driver (forked)#1354
No credential driverKeycloak credentials driver#1355
No session persistencedtach via init container#1354
No headless modeAgentTask CRD + controllerDesign doc §7

Forked Repos

UpstreamForkChanges
NVIDIA/OpenShellrossoctl/openshell--compute-driver-socket + --credentials-driver-socket flags, OIDC (PR #935)
openshell-driver-openshiftrossoctl/openshell-driver-openshiftNamespace flag, tenant labels, scoped RBAC, dtach
Newrossoctl/openshell-credentials-keycloakOAuth2 client_credentials via Keycloak (~500 lines Go)

3. Agent Deployment Tiers

Detail: sandboxing-models.md | Per-agent: agents/ Open questions: questions.md Q1.1 — 3-tier architecture, Q2.3 — credential models, Q8.1 — port bridge

Rossoctl supports three deployment tiers for agents, from simplest to most secure. The upgrade path is additive — Tier 3 agents work today and can be upgraded to Tier 2/1 incrementally without breaking existing functionality.

TierDeploymentSupervisorCredentialsOPA EgressAgent AccessExample
Tier 3K8s DeploymentNoK8s Secrets (secretKeyRef)Policy mounted, not enforcedA2A directweather, adk, claude_sdk
Tier 2Deployment + supervisor + port bridgeYes (all layers)Gateway provider injectionYes (netns + OPA proxy)A2A via port bridgeweather_supervised
Tier 1Sandbox CR via gatewayYes (all layers)Gateway provider injectionYes (netns + OPA proxy)SSH / ExecSandboxopenshell_claude, openshell_opencode

The three tiers coexist in the same namespace:

Mode 1: Custom Agents (Rossoctl-managed)

Custom A2A agents deployed as K8s Deployments. Used for production agents with custom code, frameworks (LangGraph, ADK), and A2A protocol.

  • Image: Custom Dockerfile per agent
  • Interaction: A2A JSON-RPC 2.0 (programmatic)
  • Lifecycle: Long-running Deployment
  • Examples: Weather agent, ADK agent, Claude SDK agent

Mode 2: Built-in Sandboxes (OpenShell-managed)

Pre-installed CLI agents created via OpenShell gateway. The base sandbox image (ghcr.io/nvidia/openshell-community/sandboxes/base:latest, ~1.1GB) includes Claude CLI, OpenCode, Codex, Copilot, Python, Node.js, git.

  • Image: ghcr.io/nvidia/openshell-community/sandboxes/base:latest (all CLIs pre-installed)
  • Interaction: SSH exec (interactive terminal) or openshell sandbox exec
  • Lifecycle: Ephemeral sandbox (TTL, on-demand create/destroy)
  • CRD: Sandbox CR (agents.x-k8s.io)

Pre-installed CLIs in Base Image

CLILLM ProtocolWorks with LiteLLM?Required Key
claudeAnthropic /v1/messagesYes (inference router)Anthropic or LiteLLM virtual key
opencodeOpenAI /v1/chat/completionsYes (native format)OpenAI-compatible key
codexOpenAI-specificPartialOpenAI API key
copilotGitHub Copilot APINo (proprietary)GitHub Copilot subscription

Architecture with Both Modes

Both modes share the same namespace, Budget Proxy, PostgreSQL, and Istio mesh. Custom agents use A2A protocol; built-in sandboxes use SSH/exec.


4. Sandboxing Layers

Detail: sandboxing-layers.md — supervisor, Landlock, seccomp, netns, OPA, credential isolation, LLM compatibility Conversations & HITL: conversation-and-hitl.md — multi-turn models, session persistence, HITL levels Pending questions: questions.md — 28 questions with investigation paths and test impact

Each agent pod uses the OpenShell supervisor as the container entrypoint:

  1. Supervisor starts (ENTRYPOINT)
  2. Connects to OpenShell Gateway via OPENSHELL_GATEWAY env var
  3. Reads OPA/Rego policy
  4. Applies Landlock (filesystem restrictions) + custom seccomp (syscall filtering)
  5. Drops all capabilities
  6. Execs the agent process as a restricted child

The agent inherits kernel-enforced isolation for its entire lifetime. Non-supervised agents preserve normal pod networking (Istio mesh works unchanged). The weather-agent-supervised agent enables all layers including network namespace isolation (veth pair 10.200.0.1/10.200.0.2).

5. Credential Isolation

OpenShell implements zero-secret credential isolation. Agent env vars contain placeholder tokens (openshell:resolve:env:API_KEY), not real secrets. The supervisor proxy resolves placeholders to real credentials at the HTTP layer via TLS termination before forwarding upstream.

For LLM calls, the supervisor's inference router strips agent-supplied auth headers entirely and injects backend API keys from the gateway's credential store.

6. Target Architecture (Phase 2)

Phase 2 introduces Rossoctl as an OpenShell compute driver, implementing the ComputeDriver gRPC interface (PR #817, merged). OpenShell gateway manages sandbox lifecycle; Rossoctl provisions pods with platform infrastructure (Budget Proxy, AgentRuntime CR, workspace PVC).

AuthBridge Integration (Phase 3)

Rossoctl's AuthBridge and the OpenShell supervisor are complementary security layers that cannot currently coexist in the same pod. AuthBridge provides inbound JWT validation, outbound token exchange, and SPIFFE identity. The supervisor provides Landlock, seccomp, netns, and OPA egress filtering.

Current PoC: Supervised agents disable AuthBridge injection (rossoctl.io/inject: disabled) because the supervisor's network namespace breaks AuthBridge's iptables-based traffic interception.

Phase 3 target: Combine both layers. See sandboxing-layers.md § AuthBridge + Supervisor Integration for the resolution paths and questions.md § 9 for open questions.

7. OpenShell RFC 0001

OpenShell is being rearchitected via RFC 0001 into a composable, driver-based system with four pluggable subsystems:

SubsystemPurposeRossoctl Mapping
ComputeSandbox lifecycle (K8s, Podman, VM)Rossoctl as compute driver (phase 2)
CredentialsSecret resolution (Vault, K8s Secrets)Delivers secrets to supervisor proxy
Control-plane identityUser/operator auth (mTLS, OIDC)Keycloak OIDC
Sandbox identityWorkload identity (SPIFFE)SPIRE

8. Security: Init Container Pattern (TODO)

The PoC uses privileged: true on the supervised agent container because the OpenShell supervisor needs CAP_SYS_ADMIN + CAP_NET_ADMIN for network namespace creation (unshare CLONE_NEWNET + mount --make-shared).

Current (PoC): Single container with privileged: true. The supervisor applies Landlock + seccomp after startup, but there is a window before isolation is applied where the process has full host access.

Target (production): Use an init container for the supervisor:

initContainers:
- name: supervisor-init
image: ghcr.io/nvidia/openshell/supervisor:latest
securityContext:
privileged: true # Only init container is privileged
command: ["/usr/local/bin/openshell-sandbox", "--setup-only"]
# Sets up netns, Landlock, seccomp, then exits

containers:
- name: agent
image: agent:latest
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL] # Agent has zero capabilities

The init container runs with elevated privileges for ~2 seconds (netns setup), then terminates. The agent container starts with drop: [ALL] and inherits the isolation. This eliminates the privileged window.

Requires: Upstream OpenShell support for --setup-only mode (supervisor sets up isolation and exits, leaving the netns/Landlock for the next container).

9. LLM Compatibility Matrix

Agent / CLILiteMaaS (llama-scout, deepseek)Anthropic APIOpenAI API
Claude CLI (base image)No — validates model name against Anthropic APIYes (native)No
Claude SDK agent (custom)Yes — uses httpx with OpenAI-compatible formatYes (native SDK)Yes (via format switch)
ADK agent (Google ADK)Yes — uses OpenAI-compatible format via LiteLLMN/AYes
OpenCode (base image)Yes — uses OpenAI-compatible formatN/AYes
Codex (base image)Partial — may need real OpenAI keyN/AYes
Copilot (base image)No — proprietary GitHub APIN/AN/A

Key limitation: Claude CLI requires a real Anthropic API key. It cannot use LiteMaaS or other OpenAI-compatible endpoints because it validates the model name against Anthropic's model catalog. For skill execution tests (claude /review, claude /rca:kind), a real Anthropic API key is required.

Our custom Claude SDK agent works with LiteMaaS because it uses httpx directly with the OpenAI chat/completions format, bypassing Claude CLI's model validation.

10. Egress Policy Enforcement Status

AgentSupervisor?OPA Enforced?Egress
weather-agent-supervisedYesYesTier 2
weather-agent-supervisedYesYesRestricted to *.svc.cluster.local + LiteMaaS
adk-agent-supervisedYesYes (enforced)Tier 2
claude-sdk-agentNoNo (policy mounted but not enforced)Open

Non-supervised agents have OPA policy files mounted at /etc/openshell/policy.yaml as preparation for supervisor integration. The policies are NOT enforced until the supervisor binary is the container entrypoint. Only weather-agent-supervised enforces egress control through the supervisor's HTTP CONNECT proxy + OPA engine.

Blocker for full enforcement: The supervisor creates a network namespace that blocks kubectl port-forward and K8s readiness probes. A2A tests require port-forward to reach agents from the test runner. Solutions:

  1. Upstream: supervisor exposes agent port through the proxy (not yet supported)
  2. Workaround: run tests from inside the cluster (e.g., test runner pod)
  3. Workaround: use a sidecar that bridges the netns port to the pod network

11. Phase 1 PoC Results

Detail: e2e-test-matrix.md — complete test matrix with per-agent results, future tests Test docs: tests/ — detailed per-category test documentation with architecture diagrams

The PoC validates that OpenShell runs on native Kubernetes (Kind and OpenShift/HyperShift) with all security layers active. Key results:

MetricKindHyperShift (OCP)
E2E tests total117117
E2E tests passed78-8275-76
E2E tests failed0-5 (rollout timing)0-4 (rollout timing)
E2E tests skipped3438
Agent types tested7 (4 A2A + 3 builtin)7
LiteLLM model proxyDeployed (model aliases)Deployed (model aliases)
PlatformsKind with IstioHyperShift (OCP 4.20)

Failures are intermittent — all caused by rollout timing after LLM env var patching. On a clean run with stable rollouts: 0 failures on both platforms.

Agent taxonomy (all tested)

Agent IDTypeFrameworkLLMProtocolSupervisor
weather_agentCustom A2ALangGraphNoA2A JSON-RPCNo
adk_agentCustom A2AGoogle ADKLiteMaaSA2A JSON-RPCNo
claude_sdk_agentCustom A2AAnthropic SDKLiteMaaSA2A JSON-RPCNo
weather_supervisedCustom A2ALangGraphNoA2A JSON-RPCYes (Landlock+netns+OPA)
openshell_claudeBuiltin sandboxClaude Code CLIAnthropicSSH / kubectl execYes
openshell_opencodeBuiltin sandboxOpenCode CLIOpenAI-compatSSH / kubectl execYes
openshell_genericBuiltin sandboxNone (base image)N/Akubectl execYes

Test categories

CategoryTestsWhat it validates
Platform health7Gateway, operator, agent pods, deployments
Credential isolation18secretKeyRef, no hardcoded keys, no K8s token leak, policy mounted
A2A conversations6Weather queries, PR review, code review with real LLM
Multi-turn conversations12Sequential messages, context isolation, context continuity (all agents)
Conversation survives restart8Scale-down/up + context check, pod UID changes (all agents)
PVC workspace persistence4Session state written to PVC (generic, Claude, OpenCode sandboxes)
Sandbox status observability5Gateway, deployment, pod, sandbox CR status queryable
Agent service persistence3Responds across connections, stable after delay, no restarts
Supervisor enforcement12Landlock, netns, seccomp, OPA (weather-agent-supervised)
Skill discovery5Skills ConfigMap, agent card awareness
Skill execution6PR review, RCA, security review with real LLM
Builtin sandboxes5Sandbox CR CRUD, base image, Claude/OpenCode sandbox creation
Sandbox lifecycle4List, create, delete, gateway processing

12. Phase 2: Rossoctl Backend and UI Integration

Phase 2 connects OpenShell sandboxes to the Rossoctl management plane. The backend API and UI provide session management, observability, and lifecycle control that the OpenShell gateway does not have.

Communication architecture

A2A adapters per agent type

Each agent type needs a different adapter in the Rossoctl backend to enable unified session management via the UI:

Agent TypeBackend AdapterHow it works
Custom A2A (weather, ADK, Claude SDK)A2A adapter (already implemented)Backend sends A2A message/send JSON-RPC, stores response in session DB
OpenShell builtin (Claude, OpenCode)ExecSandbox adapter (Phase 2)Backend calls gateway's ExecSandbox gRPC to send prompts, captures stdout, stores in session DB
OpenShell builtin (interactive SSH)Terminal adapter (Phase 3)Backend bridges WebSocket (xterm.js in UI) to SSH tunnel via gateway gRPC

Session persistence architecture

Context lives in the Rossoctl backend, not in the agent. This is the key architectural insight: agents can be stateless because the backend manages conversation history.

DataWhere it livesSurvives pod restart?
Conversation historyRossoctl backend PostgreSQLYes
Workspace files (code, configs)PVC mounted at /workspaceYes
Agent in-memory statePod memoryNo — lost on restart
Agent process (dtach socket)Pod filesystemNo — lost on restart

For custom A2A agents, the backend sends contextId with each request. For builtin sandboxes, the backend re-establishes the session by creating a new sandbox with the same PVC and replaying context from PostgreSQL.

What PR #1318 contributes

PR #1318 adds Sandbox CR support to the Rossoctl backend router (agents.py):

  • _build_sandbox_manifest() — creates Sandbox CRs with spec.podTemplate layout
  • _is_sandbox_ready() — status helpers for Sandbox CR state
  • Sandbox as 4th workload type in list_agents, get_agent, delete_agent, create_agent

This enables the Rossoctl UI (SandboxWizard, SandboxPage) to create and manage OpenShell sandboxes through the same API used for Deployment-backed agents.

What the Rossoctl UI already provides (OpenShell has none)

CapabilityRossoctl UI ComponentOpenShell Status
Sandbox creation wizardSandboxWizardCLI only
Session graph visualizationSessionGraphPage, TopologyGraphViewNot available
Agent catalog/discoveryAgentCatalogPage, AgentDetailPageNot available
Interactive agent chatAgentChat (A2A)SSH terminal only
LLM usage trackingLlmUsagePanelNot available
Pod status monitoringPodStatusPanelkubectl only
Prompt inspectionPromptInspectorNot available
Workspace file browsingFileBrowser, FilePreviewSSH only
Human-in-the-loop approvalHitlApprovalCardNot available
Build progress trackingBuildProgressPageNot available

13. TODO: Production Readiness

ItemPriorityDescription
Init container patternHIGHReplace privileged: true with init container (see section 9)
Enable TLS + auth on gatewayHIGHRemove --disable-tls --disable-gateway-auth, mount TLS certs
Push agent images to registryHIGHUse Shipwright on-cluster builds for OCP (manifests in shipwright-build.yaml)
Namespace-scoped NetworkPolicyMEDIUMRestrict gateway access to agent namespaces only
Audit loggingMEDIUMEnable OCSF event logging on the supervisor
Vault integrationMEDIUMReplace K8s Secrets with Vault dynamic credentials
Supervisor-managed A2A portLOWExpose agent port through supervisor proxy for netns-compatible testing
Multi-namespace supportLOWAdd RoleBindings for team2, team3, etc.

Key upstream PRs relevant to integration:

PRStatusImpact
#817MergedK8s compute driver extraction
#836OpenRFC 0001 — core architecture
#858OpenVM compute driver (proves out-of-process driver)
#822MergedL7 deny rules in policy schema
#860OpenIncremental policy updates
#861OpenSupervisor session relay