A Light‑weight, eBPF‑hardened sub‑interpreter sandbox for a no-GIL CPython
- True parallelism — built on CPython 3.13 with the
--disable-gilbuild. - Kernel‑enforced security — eBPF‑LSM & cgroup hooks gate filesystem, network, and high‑risk syscalls.
- Deterministic quotas — per‑interpreter arenas cap RAM; perf‑event BPF guards CPU & bandwidth.
- Kernel‑level accounting —
resource_guard.bpf.ctracks CPU time and RSS per sandbox via a ring buffer. - io_uring async I/O — broker uses Linux io_uring for non-blocking operations.
- Token‑gated policy reload — update YAML policies in micro‑seconds with authentication.
- Authenticated broker — X25519 (optionally Kyber‑768) + ChaCha20‑Poly1305 secure control channel with replay counters.
- Hot‑reload policy — update YAML policies in micro‑seconds without restarting guests.
- eBPF‑verified contracts — runtime assertions compiled into BPF for extra safety.
- Observability — Prometheus metrics & eBPF perf‑events for every sandbox.
- Capability imports — restrict module access per sandbox via
allowed_imports. - Restricted subset — optional interpreter with move-only ownership semantics.
- Stack canaries & CFI — sub‑interpreter compiled with
-fstack-protector-strongand-fsanitize=cfi. - NUMA‑aware scheduling — bind sandboxes to the CPUs of a chosen node on multi‑socket hosts.
- Remote policy enforcement — fetch and apply YAML over HTTP.
- Encrypted checkpointing — save sandbox state with ChaCha20‑Poly1305.
- Migration — transfer checkpoints to a peer host.
git clone https://github.com/seanwevans/pyisolate.git
cd pyisolate
python -m pip install -e .[dev] # install package for development and tooling
# Optional: enable Kyber-768 hybrid handshakes with the pqcrypto extra
# python -m pip install -e .[dev,pqcrypto]
pytest -q # run the test‑suite
python examples/echo.py
pyisolate-doctor # capture provenance + kernel/hardening feature reportThe CI pipeline runs a security/stability matrix beyond unit tests:
- adversarial and import-escape scenarios
- runaway CPU and memory exhaustion limits
- file/network policy-bypass attempts
- high-concurrency race checks (including free-threaded
3.13t) - soak runs with thousands of spawn/kill cycles on nightly schedule
- crash-injection recovery checks
- cross-kernel smoke runs on Ubuntu 22.04 and 24.04
Run the hardening suite locally with:
pytest -q tests/test_matrix_hardening.pyPyIsolate includes a pyisolate-doctor command for installation diagnostics and
release provenance tracking (Python build hash, no-GIL status, kernel features,
and deterministic-wheel policy flags). See docs/packaging-reproducibility.md.
Enable JSON-formatted logs for easier parsing:
from pyisolate.logging import setup_structured_logging
setup_structured_logging()Choose a supervisor rollout profile based on where you are deploying:
import pyisolate as iso
# default: fast local iteration
dev = iso.Supervisor(rollout_mode="dev")
# strict production posture (fail closed if BPF toolchain/load fails)
hardened = iso.Supervisor(rollout_mode="hardened")
# looser ecosystem validation (baseline BPF only, skips stricter filters)
compat = iso.Supervisor(rollout_mode="compatibility")dev: lightweight, low-friction development mode.hardened: real enforcement; any eBPF compile/load failure raises.compatibility: reduced enforcement to maximize third-party compatibility.
import pyisolate as iso
code = """
from math import sqrt
post(sqrt(2))
"""
with iso.spawn("demo", policy="stdlib.readonly") as sandbox:
sandbox.exec(code)
print("Result:", sandbox.recv()) # 1.4142135623730951Higher‑level helpers can automatically sandbox functions and build simple pipelines:
@iso.sandbox(policy="ml-inference", timeout="30s")
def run_model(data):
...
pipeline = iso.Pipeline()
pipeline.add_stage("extract", policy="readonly-fs")
pipeline.add_stage("transform", policy="compute-only")
pipeline.add_stage("load", policy="write-db")sb = iso.spawn("safe", allowed_imports=["math"])
sb.exec("from math import sqrt; post(sqrt(9))")
print(sb.recv()) # 3.0For CPython 3.13 --disable-gil deployments, review the extension and package compatibility guidance in docs/compatibility-matrix.md before expanding allowed_imports.
Run the host conformance suite to measure whether the current machine satisfies PyIsolate guarantees (Python build, kernel capabilities, BPF readiness, cgroup behavior, policy enforcement, and timeout/kill behavior):
python -m pyisolate.conformance
python -m pyisolate.conformance --jsonUse this in CI or admission checks to replace hand-wavy security claims with a repeatable pass/fail report.
Run a minimal GUI to tweak and hot‑reload YAML policies:
python -m pyisolate.editor policy/example.ymlThe debug box lets you test file paths or addresses against the live policy.
When you click Reload, the editor will ask for the policy token unless one
was supplied via PolicyEditor(token="…").
Ready-made YAML policies live in the policy/ directory. The following
templates cover common scenarios:
ml.yml– baseline for machine learning workloads with outbound HTTPS access and generous CPU/memory limits.web_scraper.yml– permits HTTP/HTTPS to the public internet while restricting filesystem access to/tmp.
Use pyisolate.policy.refresh("policy/<name>.yml", token="secret") to hot‑load any of these files at runtime.
┌──────── Supervisor (root) ───────────┐
│ • eBPF loader & maps │
│ • Broker (AEAD, counters) │
│ • Policy hot‑reloader │
│ • Metrics exporter (Prometheus) │
├──────────────────────────────────────┤
│ Thread A Thread B … Thread N │
│ ╭─────╮ ╭─────╮ ╭─────╮ │
│ │ SB1 │ │ SB2 │ … │ SBN │ │
│ ╰─────╯ ╰─────╯ ╰─────╯ │
│ ↑ ↑ ↑ │
│ │channel │ │ │
└───┴─────────┴──────────────┴─────────┘
eBPF cgroups & LSM hooks per thread
A cell is intentionally limited to seven operations: execute source, call a dotted function, import allowed modules, post messages, stream logs, emit metrics, and request broker actions.
See docs/execution-model.md. We keep this model small on purpose: production systems are safer when they refuse features outside a single contract.
- Execution cell – each guest runs in its own sub‑interpreter, hosted by one sandbox thread.
- Security boundary (authoritative) – enforcement lives at the kernel/process layer (cgroups + eBPF/LSM), not at the Python sub‑interpreter boundary.
- Kernel boundary – every sandbox thread enters its own cgroup; CO‑RE eBPF programs enforce FS/net/syscall policy.
- Broker – sole path to privileged syscalls, sealed with AEAD and strict replay protection.
- Fallback hardening – for stronger blast‑radius isolation (or kernels with reduced features), run one sandbox per process and place that process inside a container or microVM.
- Verified eBPF modules – bytecode is disassembled with
llvm-objdump -dand must succeedbpftool prog loadso the kernel verifier approves it before any sandbox runs.
See SECURITY.md for a full threat‑model walkthrough.
| Metric | Value |
|---|---|
| Spawn latency | 0.7 ms |
| Round‑trip (1 kB) | 70 µs |
| Max encrypted msgs/core | 1.9 M/s |
| Baseline RSS | 0.5 MiB |
A Dockerfile and experimental operator are included. See docs/kubernetes.md for details.
- Land Landlock fallback for unprivileged kernels
- Add Kyber‑768 / Dilithium PQ hybrids
- WASM build target for browser sandboxes
- gRPC control‑plane plugin
- Fork & create a feature branch.
- Enable
pre‑commithooks (pre‑commit install). Black handles formatting and import ordering, alongside Flake8, Pylint, and Mypy for linting. - Run
pre-commit run --all-filesand ensure CI passes. - Submit a PR with docs & tests.
MIT – see LICENSE.
Inspired by PyO3, Tetragon and libsodium.