substrate

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package substrate defines the confinement-substrate sub-interface: the seam beneath the runner.Runner surface that lets a non-OCI microVM VMM (SmolVM, Firecracker, …) back a Confinement Class alongside the OCI/Docker substrate, without the control plane (or each substrate) re-implementing the runner contract. The build-tag-free orchestrator (internal/runner/orchestrator) is the runner.Runner the control plane talks to; it multiplexes Substrates by Confinement Class and aggregates their capabilities.

A Substrate owns the mechanism of bringing up + tearing down a governed sandbox (its isolated per-run network, the wardyn-proxy sidecar, and the agent unit) on one substrate. Every Substrate MUST uphold Wardyn's non-negotiables for the sandboxes it creates:

  • Confined egress, proven EITHER of two ways — never merely asserted:
  • L0 structural: the agent has NO default route; its SOLE egress path is the wardyn-proxy sidecar (no direct off-host route). This is the docker substrate's guarantee: absence of route, not a filter to bypass.
  • L1 network-policy: a packet-filter layer (e.g. Kubernetes NetworkPolicy) default-denies the agent's egress except the proxy sidecar, AND the substrate has PROVEN that enforcement on THIS host/cluster — a policy object existing is not proof; a boot-time canary that positively confirms the deny takes effect (and refuses to boot when it does not) is. See ClassSupport.NetworkPolicy.
  • A substrate that can prove NEITHER MUST advertise no Confinement Classes at all (fail closed, never overclaim) — the sole documented exception is an explicit, operator-set opt-out env var read by that substrate. That opt-out is itself an admission of unconfined egress, not a third proof, and it MUST NOT be an invisible downgrade: the substrate (a) emits a warning at construction or CreateSandbox naming what is going unconfined, and (b) still advertises StructuralEgress=false AND NetworkPolicy=false regardless — an opted-out substrate must never read identical to a genuinely confined one on /healthz.
  • Fail closed: CreateSandbox MUST error (never silently downgrade) when the demanded Confinement Class cannot be enforced, before creating anything.
  • The run token / secrets NEVER enter the agent's environment.
  • Teardown is idempotent and reconstructable from the run id (crash-safe).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Names added in v0.3.1

func Names() []string

Names returns the registered substrate names (for /healthz and error messages).

func Register added in v0.3.1

func Register(name string, c Constructor)

Register adds a confinement-substrate implementation; call it from an init(). The OCI/Docker substrate registers itself only under `-tags docker`, so a tagless control plane fails closed at Resolve ("not registered") rather than carrying target-specific code (the parity rule).

Types

type ClassSupport

type ClassSupport struct {
	// Classes the substrate can enforce, strongest last. A class is listed ONLY
	// when its enforcing runtime is actually available (never overclaim).
	Classes []types.ConfinementClass
	// Resolved maps each available class to its substrate label ("oci/<runtime>").
	Resolved map[types.ConfinementClass]string
	// StructuralEgress reports L0 (no default route; sole egress = wardyn-proxy).
	StructuralEgress bool
	// NetworkPolicy reports L1 (a packet-filter default-deny, e.g. Kubernetes
	// NetworkPolicy, default-denying the agent's egress except the proxy
	// sidecar) — PROVEN on this host/cluster, not merely configured. A
	// substrate sets this true only after a boot-time canary has positively
	// confirmed the deny is actually enforced (see the package doc); a
	// NetworkPolicy object that exists but is silently ignored by a
	// non-enforcing CNI is exactly the false claim this field must never make.
	// StructuralEgress and NetworkPolicy are not mutually exclusive in
	// principle, but today's substrates each prove exactly one.
	NetworkPolicy bool
	// SessionRecording reports wardyn-rec PTY recording support.
	SessionRecording bool
}

ClassSupport reports the Confinement Classes a substrate can enforce on this host and the concrete substrate label backing each (e.g. CC3 -> "oci/kata-qemu"). It is the substrate-level analogue of runner.Capabilities; the orchestrator aggregates these across substrates into the runner.Capabilities it advertises.

type Constructor added in v0.3.1

type Constructor func(Deps) (Substrate, error)

Constructor builds a Substrate from Deps.

type Deps added in v0.3.1

type Deps struct {
	// ProxyImage is the wardyn-proxy sidecar image the substrate launches beside
	// each agent (the sole egress path — L0).
	ProxyImage string
	// ConfinementRuntimes are the operator's fail-closed per-class runtime pins
	// (WARDYN_CONFINEMENT_MAP); nil = the substrate's built-in defaults.
	ConfinementRuntimes map[types.ConfinementClass]string
}

Deps are the platform primitives a Substrate constructor may use. Heterogeneous seams keep their own typed Deps; an impl ignores fields it does not need (a non-OCI VMM ignores ProxyImage-as-OCI-ref semantics) and reads its own impl-specific config from the env in its constructor — see the docker impl's WARDYN_RECORDING_MOUNT / WARDYN_INTERNAL_NETWORK reads in register.go.

type Substrate

type Substrate interface {
	// Name reports the substrate kind ("docker"/OCI today), surfaced on /healthz.
	Name() string
	// Classes reports the enforceable Confinement Classes + their substrate labels.
	Classes(ctx context.Context) (ClassSupport, error)
	// CreateSandbox provisions the run's isolated network + proxy + agent unit,
	// fail-closed with full rollback on any error.
	CreateSandbox(ctx context.Context, spec runner.SandboxSpec) (runner.Sandbox, error)
	// Exec launches the agent process inside the sandbox ref, returning the
	// substrate-specific agent exec id ("" for exec-less/main-process substrates)
	// so the control plane can persist it for restart-safe liveness.
	//
	// A substrate MAY support only ONE Exec per ref over the sandbox's
	// lifetime: Kubernetes ephemeral containers are ADD-ONLY (a pod's
	// ephemeral-container list can only grow, never be replaced), so a k8s
	// substrate cannot honour a second Exec on the same ref the way the
	// docker substrate's "latest Exec wins" re-exec does today. Callers MUST
	// NOT re-Exec a ref expecting replace semantics — treat Exec as
	// one-shot per sandbox. A substrate that cannot honour a second Exec on
	// ref MUST return an error: never silently no-op, and never return the
	// PRIOR exec's id — a stale agentExecID would point AgentStatus at the
	// wrong process (fail closed; don't misreport liveness).
	//
	// This one-shot constraint is EXEC-SPECIFIC. ExecStream (below) is the
	// opposite: a substrate MUST support repeated ExecStream calls against
	// the same ref.
	Exec(ctx context.Context, ref string, argv []string) (agentExecID string, err error)
	// Wait blocks until the agent process for ref exits and returns its code.
	Wait(ctx context.Context, ref string) (int, error)
	// Attach opens an interactive PTY session inside ref.
	Attach(ctx context.Context, ref string, opts runner.AttachOptions) (runner.Session, error)
	// ExecStream launches spec.Argv inside ref as a fresh, streamable exec.
	// See runner.ExecStream's doc for the streaming, TTY-merge, and
	// invariant-3/4 security contract.
	//
	// UNLIKE Exec, ExecStream MUST be repeatable against the SAME ref: a
	// substrate MUST support many ExecStream calls against one long-lived
	// sandbox (e.g. one per SSH/SFTP channel). A k8s substrate implements
	// ExecStream on the streaming exec subresource (pods/<name>/exec —
	// repeatable, leaves no pod-spec residue), NOT an ephemeral container
	// (add-only — that limit is what makes Exec one-shot, not ExecStream).
	ExecStream(ctx context.Context, ref string, spec runner.ExecSpec) (*runner.ExecSession, error)
	// Status reports the sandbox lifecycle state.
	Status(ctx context.Context, ref string) (runner.Status, error)
	// AgentStatus reports the AGENT's state restart-safely given the persisted
	// agentExecID (inspects the exec for exec-based substrates; falls back to
	// Status when agentExecID is "").
	AgentStatus(ctx context.Context, ref, agentExecID string) (runner.Status, error)
	// StopSandbox is the graceful teardown (idempotent on a gone sandbox).
	StopSandbox(ctx context.Context, ref string) error
	// KillSandbox is the immediate kill-switch teardown (idempotent).
	KillSandbox(ctx context.Context, ref string) error
}

Substrate is runner.Runner's lifecycle contract for ONE confinement substrate, with Capabilities replaced by Classes (per-class substrate detail). The OCI substrate (internal/runner/docker) satisfies it today; a non-OCI VMM satisfies the same contract to plug into CC3.

func New added in v0.3.1

func New(name string, d Deps) (Substrate, error)

New constructs the substrate selected by name (empty => default).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL