Open-source SSH proxy with identity-aware shell (Rust)
Find a file
Tyler King 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
.github/workflows feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00
charts/bascule feat: Kubernetes native integration — Helm chart + K8s/SPIFFE config 2026-04-05 10:23:09 -04:00
config feat: Entra Agent ID auth provider + governance leak cleanup 2026-04-04 22:35:32 -04:00
crates feat: Kubernetes native integration — Helm chart + K8s/SPIFFE config 2026-04-05 10:23:09 -04:00
docs feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00
images feat: structured logging, tracing spans, comprehensive documentation 2026-04-04 23:45:03 -04:00
.gitignore feat: Bascule — identity-aware SSH proxy 2026-04-04 22:25:33 -04:00
Cargo.lock feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00
Cargo.toml feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00
docker-compose.yml feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00
Dockerfile feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00
LICENSE feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00
README.md feat: bascule-shell — identity-aware shell with TPM attestation 2026-04-05 09:47:46 -04:00

Bascule

Identity-aware SSH proxy for modern infrastructure.

Bascule is a lightweight SSH proxy that authenticates users via SSH keys or AI agent tokens, then connects them to a local shell, remote host, or ephemeral container. No agents. No control plane. One binary.

Quick Start

cargo build --release -p bascule-server
./target/release/bascule --config config/bascule.example.toml
# In another terminal:
ssh -p 2222 localhost

See docs/quickstart.md for Docker and container mode.

Session Modes

Mode Config Use case
Local PTY (default) Spawn a local shell
Remote proxy [proxy] Forward to a remote SSH host
Container [container] Ephemeral container per session

Container mode

Each SSH session spawns a fresh container. The image defines the toolset — if it's not in the image, the operator can't use it.

[container]
image = "bascule-shell:k8s-ops"
ephemeral = true
hardened = true
memory_limit = "512m"

Features

  • Three backends — local PTY, remote SSH proxy, ephemeral containers
  • Identity-aware sessions — every connection authenticated and attributed
  • SSH key authentication — standard authorized_keys file
  • AI agent authentication — Microsoft Entra Agent ID support (optional feature)
  • Session limiting — configurable max concurrent sessions
  • Right-sized images — curated container images (minimal, k8s-ops, net-ops, dev)
  • SessionHandler trait — extend with custom policy, audit, or recording
  • Structured logging — JSON format for production observability
  • Small footprint — single binary, ~7MB, <64MB memory

Comparison

Bascule Teleport Boundary
Agents None Required Required
Control plane None Required Required
License Apache 2.0 AGPL MPL
Container sessions Native No No
AI Agent Identity Native No No
Auth SSH keys, Entra Agent ID OIDC, SAML, GitHub OIDC, LDAP
Binary size ~7MB ~150MB ~100MB

See docs/comparison.md for the full comparison.

Extending Bascule

Implement the SessionHandler trait to add custom behavior:

use bascule_core::hooks::{SessionHandler, SessionInfo};

struct MyAuditHandler;

#[async_trait]
impl SessionHandler for MyAuditHandler {
    async fn on_session_start(&self, session: &SessionInfo) -> anyhow::Result<()> {
        log::info!("{} connected from {}", session.principal, session.source_ip);
        Ok(())
    }

    async fn on_exec(&self, session: &SessionInfo, command: &str) -> anyhow::Result<()> {
        log::info!("{} executed: {}", session.principal, command);
        Ok(())
    }
}

Projects like Guildhouse use the SessionHandler trait to add custom authorization, audit logging, and session governance.

Documentation

Roadmap

  • OIDC authentication (Keycloak, Entra, Okta, Google)
  • Certificate-based authentication
  • OpenTelemetry OTLP trace export
  • Prometheus metrics endpoint
  • Session recording
  • Web UI for session management

License

Apache 2.0