Skip to main content

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

  1. Tenant admin issues an enrollment token.
  2. Endpoint agent enrolls and reports heartbeat telemetry with SSH capability.
  3. Operator opens the Assets page and selects the enrolled asset.
  4. Operator requests a browser SSH grant with a reason and bounded duration.
  5. Platform validates tenant scope, role, active/enrolled agent identity, SSH-capability evidence, idempotency, and tenant session limits.
  6. Platform creates an approved grant and append-only audit evidence.
  7. Browser connects to /api/v1/rmm/ssh-sessions/{session_id}/ws.
  8. The xterm.js terminal stays read-only while the grant is pending.
  9. Gateway sends open_tunnel to the registered agent over /api/v1/agents/control-channel.
  10. Status becomes active only after the agent emits tunnel_opened; the gateway emits session.ssh.started.
  11. Terminal input is enabled only after the browser receives session_active.
  12. Broker command-log API is accepted only for active sessions, records redacted command summaries, and emits session.ssh.command_logged.
  13. 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, and session.ssh.ended is 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.py covers 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.py validates SSH session list/detail response shapes after an agent heartbeat and gateway activation.
  • tests/test_ssh_gateway.py pins 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.py pins SQLite/Postgres schema parity for ssh_sessions and ssh_command_logs.
  • make aws-dev-helm-render renders 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.