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:
- Fetch
/health.
- Verify the TDX quote and confirm it binds
noise.pubkey_hex.
- Open
/noise/ws using the pinned server static key.
- Authenticate as a paired device key.
- 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.
Context
The current remote-attestation story is split across two surfaces:
/healthexposesnoise.quote_b64andnoise.pubkey_hex, letting a client verify that the Noise static key is bound into a TDX quote./noise/wsgives paired devices an attested Noise_IK channel to the EE agent socket.dd-shellgives operators a strong browser terminal UX, but its active session path is still GitHub-cookie auth plus/ws/sessions/{id}tosessiond.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.rsintonoise_gatewaywholesale.Keep
shell.rsas the browser/PWA/session-management UI, but expose the shell/sessiond operations through a small Noise RPC surface:The client flow becomes:
/health.noise.pubkey_hex./noise/wsusing the pinned server static key.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:
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.rsalready supports anattachmethod that switches from JSON request/response into a raw bidirectional encrypted byte bridge.src/noise_gateway/attest.rsalready binds the Noise static pubkey into the TDX quote surfaced via/health.src/shell.rsalready has the terminal/session UI and/ws/sessions/{id}raw PTY bridge tosessiond.src/sessiond.rsalready 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
attachstreaming pattern for PTY bytes.sessiondHTTP and attach socket operations.Acceptance criteria
/healthquote material, pinnoise.pubkey_hex, and open/noise/ws.