Browser SSH Broker Runtime
Summary
OP-062 implements the platform-side browser SSH broker lifecycle. The follow-on gateway stream adds the platform in-process WebSocket relay that pairs with the standalone endpoint agent control channel. Operators, tenant admins, and system admins can request tenant-scoped JIT SSH grants for enrolled agents that have reported SSH capability. Auditors can inspect session evidence but cannot create or end sessions.
The Assets console now renders browser SSH session request/history state from
real APIs and exposes an xterm.js terminal for approved/active grants. The
terminal connects to the real /api/v1/rmm/ssh-sessions/{session_id}/ws relay,
waits for session_active, sends terminal input as relay bytes, and renders
pending, closed, and error states without fake command output.
AWS dev app ingress is configured with an ALB idle timeout of 3600 seconds so
operator SSH terminals and agent control-channel waits are not cut off by the
default 60-second load balancer idle timeout. The protected
AWS_DEV_HELM_VALUES_FILE must preserve the same annotation before live SSH
journey validation.
The agent control-channel registration persists control_channel and
tunnel.ssh capability evidence onto the tenant-scoped agent identity and asset
read model. The Assets console uses that same persisted capability evidence,
not only open-port observations, before enabling the browser SSH request flow.
Persona Journey
- Tenant admin issues an enrollment token.
- Endpoint agent enrolls and reports heartbeat telemetry with SSH capability.
- Operator opens the Assets page and selects the enrolled asset.
- Operator requests a browser SSH grant with a reason and bounded duration.
- Platform validates tenant scope, role, active/enrolled agent identity, SSH-capability evidence, idempotency, and tenant session limits.
- Platform creates an
approvedgrant and append-only audit evidence. - Browser connects to
/api/v1/rmm/ssh-sessions/{session_id}/ws. - The xterm.js terminal stays read-only while the grant is pending.
- Gateway sends
open_tunnelto the registered agent over/api/v1/agents/control-channel. - Status becomes
activeonly after the agent emitstunnel_opened; the gateway emitssession.ssh.started. - Terminal input is enabled only after the browser receives
session_active. - Broker command-log API is accepted only for
activesessions, records redacted command summaries, and emitssession.ssh.command_logged. - Operator cancels the grant, the browser disconnects, or the agent sends
tunnel_closed; recording metadata is sealed with a SHA-256 hash when relay evidence exists, audit is appended, andsession.ssh.endedis emitted.
Security Boundary
- No persistent SSH key vault is introduced.
- The browser never receives private keys.
- Commands are redacted before persistence when sensitive content is detected.
- Session recordings are represented by encrypted tenant-scoped references; raw recording bytes are not returned by the API.
- Auditors can read session evidence only; mutation is denied and auditable.
- Cross-tenant session reads remain denied by tenant-scoped queries.
- Command logs are advisory until a future parser derives transcript entries
from server-observed relay bytes. The broker denies command logs for grants
that have not reached
active. - Idle and absolute timeouts are stored with the grant. The endpoint agent control channel is the source of truth for tunnel-open/tunnel-closed lifecycle events; the platform gateway reflects those signals into session state.
Validation
tests/test_phase1_persona_journeys.pycovers the enrollment -> heartbeat -> SSH grant request -> gateway activation -> active-only command log -> session end journey, plus auditor denial and cross-tenant denial.tests/test_frontend_response_contracts.pyvalidates SSH session list/detail response shapes after an agent heartbeat and gateway activation.tests/test_ssh_gateway.pypins the 36-byte tunnel-id binary frame prefix and agent-to-browser relay behavior, and verifies that agent control-channel registration persists SSH capability evidence for the broker/UI read path.- The Assets console tests verify that an SSH-capable enrolled asset exposes
the request path, refreshes after mutation, opens the real session WebSocket
path, waits for
session_active, and sends terminal input as binary relay bytes. scripts/validate_schema_read_models.pypins SQLite/Postgres schema parity forssh_sessionsandssh_command_logs.make aws-dev-helm-renderrenders the AWS dev app Ingress with the ALB WebSocket idle-timeout annotation used by the live terminal path.
Non-Scope
This stream does not implement server-derived command parsing, full recording object storage, remote desktop, file transfer, patching, or software deployment. AWS dev ingress tuning is limited to the app ALB idle-timeout guardrail for the existing browser SSH WebSocket paths.