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>
4.7 KiB
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:
#[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:
#[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 |