Skip to content

Improve RA story by routing shell sessions over Noise #262

@posix4e

Description

@posix4e

Context

The current remote-attestation story is split across two surfaces:

  • /health exposes noise.quote_b64 and noise.pubkey_hex, letting a client verify that the Noise static key is bound into a TDX quote.
  • /noise/ws gives paired devices an attested Noise_IK channel to the EE agent socket.
  • dd-shell gives operators a strong browser terminal UX, but its active session path is still GitHub-cookie auth plus /ws/sessions/{id} to sessiond.

That means the shell is useful, but the statement "this terminal data plane is encrypted to the enclave key I verified by RA" is indirect. We can make the RA story clearer by letting shell/session operations ride over the existing Noise channel.

Proposal

Combine the shell and Noise paths at the protocol boundary, not by folding shell.rs into noise_gateway wholesale.

Keep shell.rs as the browser/PWA/session-management UI, but expose the shell/sessiond operations through a small Noise RPC surface:

  • create session
  • attach session as a raw encrypted byte stream
  • resize session
  • close session
  • list/replay sessions and workload logs where appropriate

The client flow becomes:

  1. Fetch /health.
  2. Verify the TDX quote and confirm it binds noise.pubkey_hex.
  3. Open /noise/ws using the pinned server static key.
  4. Authenticate as a paired device key.
  5. Run shell/session RPCs and PTY bytes inside the Noise transport.

The browser shell can remain a convenience operator UI. A bastion/native/CLI client can become the canonical RA-backed terminal client because it can hold the device private key and perform quote verification outside browser storage constraints.

Why this helps

This lets us make a much cleaner security claim:

Terminal control and PTY bytes are encrypted to a TDX-attested Noise key, and the enclave only accepts paired device keys.

That is stronger than the current split story where the dashboard exposes an attestation bundle and the browser terminal uses a separate authenticated WebSocket path.

Existing code that helps

  • src/noise_gateway/noise.rs already supports an attach method that switches from JSON request/response into a raw bidirectional encrypted byte bridge.
  • src/noise_gateway/attest.rs already binds the Noise static pubkey into the TDX quote surfaced via /health.
  • src/shell.rs already has the terminal/session UI and /ws/sessions/{id} raw PTY bridge to sessiond.
  • src/sessiond.rs already centralizes multi-session PTY lifecycle.

The likely implementation is to add a Noise-facing shell/session adapter rather than duplicate the PTY/session code.

Possible implementation steps

  • Define a small shell RPC schema for Noise requests, separate from raw EE agent-socket methods if needed.
  • Reuse the existing Noise attach streaming pattern for PTY bytes.
  • Add an adapter from Noise requests to sessiond HTTP and attach socket operations.
  • Keep browser routes working during the transition.
  • Add docs that distinguish convenience browser shell from RA-backed shell client.
  • Add tests for method allowlisting and attach stream behavior.

Acceptance criteria

  • A client can verify /health quote material, pin noise.pubkey_hex, and open /noise/ws.
  • A paired device can create and attach to a shell session over Noise.
  • PTY input/output for the session flows only inside Noise transport for the RA-backed path.
  • Existing browser shell routes continue to work unless intentionally deprecated in a separate change.
  • Docs explain the security boundary in concrete terms: quote verification, pinned Noise key, paired device key, encrypted terminal data plane.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions