bascule-oss/docs/architecture.md
Tyler King 6eb2de5dc0 docs: update all documentation for management API + dashboard
Updated 9 files to reflect:
  Management API (axum, port 9090) — embedded in bascule-server
  Dioxus dashboard components (WASM web target)
  6 crates in workspace (was 4)

README.md:
  Added Management API + Dashboard features section
  Added dashboard row to comparison table

docs/architecture.md:
  Updated diagram showing dual-listener architecture
  Added Management API section explaining Arc<SessionStore> sharing
  Updated crate table (6 crates)

docs/configuration.md:
  Added [dashboard] config section reference

docs/observability.md:
  Added Management API monitoring section with curl examples

docs/quickstart.md:
  Added Management API quick start section

docs/comparison.md:
  Added dashboard and TPM attestation rows

CLAUDE.md + CONTRIBUTING.md:
  Updated crate lists and feature flags

config/bascule.example.toml:
  Added [dashboard] section

All 17 README links verified valid. Build clean.

Signed-off-by: Tyler King <tking@guildhouse.dev>
2026-04-05 17:17:18 -04:00

107 lines
4.7 KiB
Markdown

# Architecture
## Overview
Bascule is a single-binary SSH proxy with a built-in management API:
```
┌─────────────────────────────────────┐
Operator workstation │ bascule (single binary) │
┌───────────────┐ │ │
│ bascule-shell │ SSH │ Port 2222: SSH Proxy (russh) │
│ identity + │─────▶│ ├── AuthProvider │
│ TPM attest │ │ ├── SessionHandler hooks │
└───────────────┘ │ └── SessionBackend │
│ ├── Local PTY │
Browser / curl │ ├── Remote Proxy │
┌───────────────┐ HTTP │ └── Container │
│ Dashboard │─────▶│ │
│ /api/* │ │ Port 9090: Management API (axum) │
└───────────────┘ │ ├── /api/sessions │
│ ├── /api/stats │
│ ├── /api/health │
│ └── /dashboard (WASM, planned) │
│ │
│ Arc<SessionStore> shared │
└─────────────────────────────────────┘
```
## Session Backends
### Local PTY (default)
Spawns a process on this machine via `portable-pty`. The process gets a real PTY with terminal emulation, resize support, and environment variables.
### Remote Proxy
Opens a second SSH connection to a target host via `russh` client. Bridges I/O between the client and upstream channels. The client sees a transparent connection to the target host, but Bascule mediates authentication and applies SessionHandler hooks.
### Container
Spawns an ephemeral container per session using docker, podman, or nerdctl. The container is destroyed on disconnect. The container image defines what tools are available — if it's not in the image, the operator can't use it.
## Extension Model
### AuthProvider trait
Implement to add custom authentication:
```rust
#[async_trait]
pub trait AuthProvider: Send + Sync + 'static {
async fn check_public_key(&self, user: &str, key: &PublicKey) -> bool;
async fn check_password(&self, user: &str, password: &str) -> bool;
fn principal_for_user(&self, user: &str) -> String;
}
```
### SessionHandler trait
Implement to add policy, audit, or custom behavior:
```rust
#[async_trait]
pub trait SessionHandler: Send + Sync + 'static {
async fn on_session_start(&self, session: &SessionInfo) -> anyhow::Result<()>;
async fn build_session_env(&self, session: &SessionInfo) -> HashMap<String, String>;
async fn on_exec(&self, session: &SessionInfo, command: &str) -> anyhow::Result<()>;
async fn on_session_end(&self, session: &SessionInfo) -> anyhow::Result<()>;
fn display_name(&self, session: &SessionInfo) -> String;
}
```
All methods have default implementations (accept/passthrough). Override only what you need.
## Security Model
### Container hardening (default)
When `hardened = true`:
- `--security-opt no-new-privileges`
- `--cap-drop ALL`
- `--cap-add SETUID --cap-add SETGID` (minimal for shell)
### Ephemeral sessions
When `ephemeral = true` (default), the container is `--rm` and destroyed on disconnect. Nothing persists between sessions.
### Network isolation
Set `network = "none"` to completely isolate the container from the network. The operator can run local tools but can't reach external services.
## Management API
The management API runs alongside the SSH proxy in the same process. Both share an `Arc<SessionStore>` — when a session starts via SSH, the store updates; when the dashboard polls `/api/sessions`, it reads the same store. Zero serialization, zero IPC.
Enable via `[dashboard]` config section or `--features dashboard` (default on).
## Crate Structure
| Crate | Purpose |
|-------|---------|
| `bascule-core` | Library — server, handler, auth, PTY, proxy, container, hooks, store |
| `bascule-server` | Binary — CLI, config, tracing, management API |
| `bascule-auth-agent-id` | Optional — Entra Agent ID authentication |
| `bascule-shell` | Binary — Identity-aware login shell with TPM |
| `bascule-dashboard` | Library — Dioxus UI components |
| `bascule-dashboard-web` | Binary — WASM web dashboard target |