Commit graph

8 commits

Author SHA256 Message Date
04dd74d15f feat: Dioxus dashboard — session analytics + WASM web target
New crates:
  bascule-dashboard — shared Dioxus component library
    SessionTable: live active sessions with auth/backend/TPM status
    StatsCards: active count, 24h total, TPM attested %, failed auth
    StatusBar: connection health indicator
    types.rs: DashboardSession, DashboardStats, HealthResponse

  bascule-dashboard-web — WASM web target (Dioxus 0.6 + web features)
    Compiles to wasm32-unknown-unknown
    Dark-first CSS (light mode via prefers-color-scheme)
    Monospace data display, clean stat cards

  bascule-core/store.rs — in-memory session store
    SessionStore with active sessions + aggregate stats
    Updated via SessionHandler hooks

Both dashboard library and web WASM target compile clean.
Server and shell builds unaffected. Zero substrate deps.

Signed-off-by: Tyler King <tking@guildhouse.dev>
2026-04-05 14:10:01 -04:00
9dc5cb9eee feat: Kubernetes native integration — Helm chart + K8s/SPIFFE config
Helm chart (charts/bascule/):
  Deployment with shell sidecar container (shared jumphost model)
  Service (LoadBalancer/NodePort/ClusterIP)
  ConfigMap with auto-generated config.toml
  RBAC (Role + RoleBinding for pods/exec)
  NetworkPolicy (restrict shell egress, allow DNS + K8s API)
  ServiceAccount with create flag
  Configurable shell image (k8s-ops, net-ops, dev, minimal)
  Helm lint passes clean

K8s backend config (bascule-core):
  [k8s] section: enabled, namespace, pod_name, shell_container, shell
  Auto-detection via POD_NAME/POD_NAMESPACE env vars (downward API)
  Backend priority: K8s > proxy > container > local PTY
  K8s exec implementation deferred to --features k8s (kube crate)

SPIFFE/SPIRE auth config:
  [auth.spiffe] section: trust_domain, trust_bundle_path, workload_api_socket
  JWT-SVID token-as-password authentication pattern
  Implementation deferred to bascule-auth-spiffe crate

Zero substrate dependencies. Default build unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 10:23:09 -04:00
043b9b9bdc feat: bascule-shell — identity-aware shell with TPM attestation
New crate: bascule-shell (471 lines, 1.8MB binary)
  Login shell that detects identity + platform attestation at startup.
  Wraps bash/zsh/fish — operator works normally, identity travels with them.

Identity detection (priority order):
  1. Entra via WSL2 interop
  2. Azure CLI
  3. Kerberos TGT
  4. Cached OIDC token
  5. System user (fallback)

Platform attestation:
  TPM 2.0 PCR values via tpm2_pcrread (PCRs 0,1,2,7,10,14)
  IMA measurement log hash + count
  Keylime agent state
  Entra device compliance (WSL2 only)
  Composite SHA-256 hash over all evidence

Shell features:
  Banner with identity + attestation summary
  BASCULE_* env vars injected into inner shell
  --info mode for dry-run display
  --json mode for machine-readable output
  --exec mode for single-command execution
  Configurable via ~/.config/bascule/shell.toml

Tested on Fedora with real TPM 2.0:
  6 PCRs successfully read from hardware
  All env vars propagated to inner shell
  1.8MB binary, 0 substrate deps

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 09:47:46 -04:00
e7fc9fa5e1 feat: structured logging, tracing spans, comprehensive documentation
Observability:
  Structured JSON logging via BASCULE_LOG_FORMAT=json
  Tracing spans on auth (method, principal, peer)
  Tracing spans on session lifecycle (id, principal, backend, source_ip)
  Tracing spans on exec requests (session_id, command)
  Config: [telemetry] and [metrics] sections (OTel export planned)

Documentation (8 files, 489 lines):
  docs/quickstart.md — three-path getting started
  docs/configuration.md — full config reference with examples
  docs/authentication.md — all auth modes with setup guides
  docs/architecture.md — backends, traits, extension model, security
  docs/observability.md — logging, tracing, metrics
  docs/comparison.md — vs Teleport, Boundary, StrongDM
  images/README.md — curated image catalog
  README.md — features, comparison, quickstart, extension example

1557 lines Rust, 489 lines docs, 0 substrate deps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:45:03 -04:00
8d789524e8 feat: container backend — ephemeral right-sized shell containers
Third session backend: per-session ephemeral containers.
SSH session → container spawns → operator works → disconnect → destroyed.

Container runtime abstraction:
  Docker, Podman, Nerdctl via CLI execution (auto-detect)
  No libdocker dependency — any OCI-compliant runtime

Container config ([container] section):
  image, pull_policy, mounts, env, memory/cpu limits
  ephemeral (destroy on exit), hardened (drop caps)
  read_only_rootfs, network mode, user override

Handler: SessionBackend enum now has three variants:
  Local(PtyBridge) — spawn local shell
  Proxy(UpstreamSession) — forward to remote SSH host
  Container(ContainerSession) — spawn ephemeral container
  Priority: proxy > container > local PTY

Curated base images (images/):
  minimal — bash, coreutils, curl, jq, ssh (~50MB)
  k8s-ops — + kubectl, helm (~120MB)
  net-ops — + nmap, dig, traceroute, tcpdump (~90MB)
  dev — + git, make, gcc, python3 (~250MB)

The container IS the access boundary:
if it's not in the image, the operator can't run it.

SessionHandler hooks fire in all three modes.
6.5MB binary, 0 substrate deps, 1197 lines bascule-core.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:23:39 -04:00
2212f7f870 feat: remote SSH proxy mode
Bascule now supports two session modes:
  Local — spawns a PTY on this machine (default, existing)
  Proxy — forwards the session to a target SSH host (NEW)

Proxy mode:
  SSH client ←→ bascule (auth + hooks) ←→ target SSH host
  Authenticates client via configured auth provider
  Connects to upstream SSH host via russh client
  Bridges I/O between client and upstream channels
  PTY, shell, and exec requests forwarded to target
  Exit status propagated back to client

Config:
  [proxy]
  target_host = "192.168.1.100"
  target_port = 22
  target_user = "deploy"           # optional, defaults to principal
  target_key_path = "/etc/bascule/target_key"
  accept_target_host_key = false   # dev only

SessionHandler hooks fire in both modes:
  on_session_start, on_exec, on_session_end
  Custom handlers can enforce policy regardless of mode

New file: proxy.rs (152 lines)
  UpstreamHandler — minimal russh client handler
  connect_upstream — connects + authenticates to target
  bridge_upstream_to_client — bidirectional I/O bridge

Binary: 6.3MB, zero substrate deps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:01:08 -04:00
02142f7be4 feat: Entra Agent ID auth provider + governance leak cleanup
New crate: bascule-auth-agent-id
  Microsoft Entra Agent ID authentication for AI agents
  Validates OAuth tokens against Entra JWKS (60min cache)
  Extracts agent metadata: type, blueprint, sponsor, scopes
  Detects on-behalf-of (delegated) agents
  Token-as-password pattern for SSH auth

Cleanup:
  Removed all governance-specific references from comments
  SessionHandler trait is the only extension point
  Zero substrate/chronicle/gsap dependencies
  Config example uses neutral terminology

Config:
  [auth.agent_id] section for Entra configuration
  tenant_id, audiences, multi_tenant fields

3 crates: bascule-core, bascule-server, bascule-auth-agent-id
938 lines total, 5.6MB binary, 0 substrate deps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:35:32 -04:00
bfa26cfd15 feat: Bascule — identity-aware SSH proxy
Open-source SSH proxy with pluggable authentication and
extensible session handling. Zero external governance dependencies.

Core (bascule-core):
  russh 0.46 SSH server with PTY bridge (portable-pty)
  Pluggable auth: AuthProvider trait (SSH keys, accept-all dev mode)
  SessionHandler trait for extending behavior (audit, governance)
  TOML configuration, ephemeral Ed25519 host key generation

Binary (bascule-server):
  Single binary, 5.6MB release build
  CLI with --config flag
  Default: accept-all auth on port 2222

Extension points:
  AuthProvider — implement for OIDC, certificates, custom auth
  SessionHandler — implement for audit, governance, recording
  DefaultHandler — passthrough (ships with open-source version)

Zero substrate/chronicle/gsap/hfl dependencies.
Apache 2.0 License.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:25:33 -04:00