A zero-trust routing hub for running autonomous AI agents safely. Bastion sits between the open internet and your local agents, enforcing hard security boundaries before any code executes on your host.
Built in Rust on Axum. Lean, fast, and deployable on ARM64.
Internet / Agents
│
┌────▼────────────────────────────────────────────┐
│ Ingress Firewall (axum reverse proxy) │
│ • Validates all webhooks and WebSocket events │
│ • Drops malformed requests before routing │
└────┬────────────────────────────────────────────┘
│
┌────▼────────────────────────────────────────────┐
│ API Security Layer │
│ • Per-IP rate limiting (tower-governor) │
│ • Configurable payload size cap │
│ • Authorization header enforcement │
└────┬────────────────────────────────────────────┘
│
┌────▼────────────────────────────────────────────┐
│ Cognitive Firewall │
│ • Static regex blocklist (jailbreak strings, │
│ system-prompt overrides, shell signatures) │
│ • serde + validator schema enforcement │
└────┬────────────────────────────────────────────┘
│
┌────▼────────────────────────────────────────────┐
│ Routing Layer │
│ • /api/v1/llm — LLM proxy endpoint │
│ • /api/v1/sandbox/run — ephemeral execution │
│ • /ws — WebSocket ingress │
│ • /health /ready — liveness probes │
└────┬────────────────────────────────────────────┘
│
┌────▼────────────────────────────────────────────┐
│ Sandbox Manager (bollard / Docker) │
│ • Ephemeral isolated containers per task │
│ • Hard TTL — runaway containers are killed │
│ • No network, read-only FS, capped CPU/RAM │
└─────────────────────────────────────────────────┘
The Sandbox is the ultimate failsafe. Even if an adversarial payload slips past every layer above it, the container is a dead end — no network, no host filesystem, and a hard timeout that kills it if an agent loops forever.
All settings live in bastion.toml at the same directory as the binary. Every field is optional; the defaults are production-ready out of the box.
[api]
listen_addr = "0.0.0.0:8080"
upstream_base = "http://localhost:3001"
max_body_bytes = 1_048_576 # 1 MiB
[rate_limit]
requests_per_second = 5
burst_size = 10
[sandbox]
default_image = "alpine:latest"
memory_bytes = 134_217_728 # 128 MiB
cpu_quota = 50_000 # 50% of one vCPU
read_only = true
ttl_seconds = 30 # hard kill after 30 s
max_pids = 64Environment variables override bastion.toml for deployment-time injection:
| Variable | Overrides |
|---|---|
LISTEN_ADDR |
api.listen_addr |
UPSTREAM_BASE |
api.upstream_base |
RUST_LOG |
log filter (tracing) |
| Method | Path | Description |
|---|---|---|
GET |
/health |
Liveness probe — returns 200 ok |
GET |
/ready |
Readiness probe — same as /health |
POST |
/api/v1/llm |
Submit a chat payload; cognitive firewall runs |
POST |
/api/v1/sandbox/run |
Run a command in an ephemeral Docker container |
GET |
/ws |
WebSocket ingress |
* |
/* |
Catch-all reverse proxy to upstream_base |
{
"model": "llama3",
"messages": [
{ "role": "user", "content": "What is the capital of France?" }
],
"temperature": 0.7
}Returns the sanitized payload after the cognitive firewall has run. Flagged messages are stripped; if the entire payload is adversarial, 400 is returned.
{
"image": "alpine:latest",
"command": ["sh", "-c", "echo hello"],
"ttl_seconds": 10
}All fields except command are optional and fall back to bastion.toml. Returns stdout, stderr, and exit code.
{
"stdout": "hello\n",
"stderr": "",
"exit_code": 0
}cargo build --release
RUST_LOG=info ./target/release/hubdocker compose up -dThe hub mounts the host Docker socket (/var/run/docker.sock) so it can spawn sibling containers for sandbox execution. ARM64-compatible.
| Threat | Mitigation |
|---|---|
| Endpoint hammering | Per-IP rate limiting via tower-governor |
| Oversized payloads | Configurable byte cap, enforced before parsing |
| Missing auth | Authorization header required on all non-probe routes |
| Prompt injection | Static regex blocklist strips known jailbreak patterns |
| Malformed LLM schema | serde + validator rejects at deserialization |
| Runaway agent (infinite loop) | Container TTL — hard SIGKILL after ttl_seconds |
| Lateral movement | NetworkMode::None on all sandbox containers |
| Host filesystem access | readonly_rootfs: true by default |
| Privilege escalation | cap_drop: ALL, no-new-privileges: true |
| Fork bombs | pids_limit enforced via Docker |
- OpenTelemetry (OTLP) — export spans to Prometheus / Grafana / Datadog
- SSE streaming — stream LLM token chunks directly to clients
- Human-in-the-Loop hooks — pause agent execution on high-stakes actions pending signed operator approval
- MCP host — register and route Model Context Protocol tool servers