Getting Started with NaZelo¶
This takes you from a fresh install to running a command in the sandbox, collecting its evidence, and verifying a signed capability token. About five minutes. For the full technical reference, see REFERENCE.md.
1. Install¶
Requires Python 3.12. Runtime dependencies: blake3 and click.
2. Generate a signing key¶
NaZelo signs its capability tokens with a keyed BLAKE3 MAC. Generate one 32-byte key and export it. Store it like any other secret.
# 64 hex chars = 32 bytes
export NAZELO_SIGNING_KEY="$(python3 -c 'import os; print(os.urandom(32).hex())')"
3. Run your first command¶
You will see:
nazelo run streams the sandboxed command's stdout and stderr through to your
terminal, then exits with the same exit code as the sandboxed process. The
dev preset uses TL1 (bwrap), the fastest tier.
4. See the structured result¶
Add --json when you want to consume the result programmatically:
{
"run_id": "…",
"exit_code": 0,
"stdout": "42\n",
"stderr": "",
"backend": "sandbox_tl1",
"verified": true
}
verified: true means verification was requested and the command exited 0.
run_id is the correlation key stamped into every evidence event for this run.
5. Check which backends are available¶
TL Label Backend Tool Status
----------------------------------------------------------------------
1 LOCAL sandbox_tl1 bwrap OK
2 CONTAINED sandbox_tl2 unshare OK
3 ISOLATED sandbox_tl3 runsc --
4 HARDENED sandbox_tl4 firecracker --
OK means the backend's probe succeeded; -- means the required tool is not on
PATH. Install the missing tool (bubblewrap, util-linux, gVisor, Firecracker) to
light up higher tiers — see REFERENCE.md.
6. Collect the evidence¶
Every sandbox lifecycle event — create, exec, destroy — is recorded through the
EvidenceRecorder protocol. Provide your own recorder to capture the audit
trail:
from datetime import datetime
from pathlib import Path
from nazelo import (
VerificationResult, SandboxProfile, TrustLevel2Backend,
ExecutionRequest, issue_token, new_execution_profile,
)
class MyRecorder:
def __init__(self):
self.audit_log = []
def record_sandbox_event(self, event: str, details: dict) -> VerificationResult:
self.audit_log.append({"event": event, **details})
return VerificationResult(
verified=True, evidence_type=event,
details=details, timestamp=datetime.now(),
)
profile = new_execution_profile(SandboxProfile.for_ci(owner="ci-bot"))
token = issue_token(profile)
recorder = MyRecorder()
backend = TrustLevel2Backend(
workspace_path=Path.cwd(),
token=token,
profile=profile,
evidence_recorder=recorder,
)
backend.execute(ExecutionRequest(command="echo audited", timeout=30))
for entry in recorder.audit_log:
print(entry["event"]) # sandbox.create, sandbox.exec, sandbox.destroy
Each entry is a structured record you can feed to a compliance layer. See the full event list for what NaZelo emits.
7. Verify a capability token¶
Tokens are signed and time-bounded. Issue one, then verify its signature and TTL:
nazelo token issue --owner ci-bot -t 2 -c exec
# prints the signature, sandbox id, ttl, and issued-at time
nazelo token verify <SIGNATURE> -t 2 --owner ci-bot \
--sandbox-id <ID> --ttl <SECS> -c exec --issued-at <ISO>
A tampered or expired token fails verification. Every field in the command above is part of the signed payload, so changing any one of them breaks the signature.
Next steps¶
- Trust levels, network rules, L7 stream-proxy enforcement, seccomp process governance, the full CLI and Python API → REFERENCE.md
- Building the TL4 Firecracker kernel and rootfs →
firecracker/README.md