Skip to content

feat(gvisor): selectable gVisor runtime tier for tenant sandboxes - #9

Merged
snese merged 7 commits into
mainfrom
feat/gvisor-runtime-tier
Jul 14, 2026
Merged

feat(gvisor): selectable gVisor runtime tier for tenant sandboxes#9
snese merged 7 commits into
mainfrom
feat/gvisor-runtime-tier

Conversation

@snese

@snese snese commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

What

Adds a selectable gVisor (runsc) kernel-isolation tier to tenant Sandboxes on the all-Graviton (ARM64) EKS cluster, without disturbing the runc tier from #6. Part of #5.

  • CDK: gvisor RuntimeClass (handler: runsc) + tainted Karpenter NodePool (AL2023 ARM64, runsc + containerd-shim-runsc-v1 via EC2NodeClass userData) + EC2NodeClass.
  • Helm: per-tenant SandboxTemplate selects the tier via sandbox.runtimeClassName: gvisor (adds the gVisor pool nodeSelector + NoSchedule toleration). Default stays runc.
  • ADR-0007 documents the decision, Phase 0 gates, and verification evidence.
  • Uniform Pod Identity model across both tiers (no IRSA divergence — verified reachable under gVisor).

Verification (live, not just synth/lint)

Fresh cdk deploy of the full stack on a net-new stack (us-east-1):

  • Stack reached CREATE_COMPLETE.
  • runtimeClassName=gvisor pod scheduled by Karpenter onto an openclaw/runtime=gvisor arm64 node → /proc/version = Linux 4.19.0-gvisor, uname -m = aarch64, dmesg "Starting gVisor..." (gVisor kernel, not host).
  • Pod Identity (169.254.170.23 → tenant role), EFS RWX mount, and a real OpenClaw image (Node.js 24 + crypto + Bedrock) all verified under gVisor on arm64.
  • runc tier unchanged (gVisor pool is tainted; only gvisor-RuntimeClass pods land there).

CI green: Platform (CDK + Helm + Scripts), CodeQL, Security scan.

Notes

  • agent-sandbox gVisor scheduling fields validated against v0.4.5 — re-validate on upgrade.
  • gVisor caveats (documented in ADR-0007): partial iptables, subset of syscall ABI (workload-dependent), service-mesh sidecars awkward (prefer ambient/sidecarless or Kata).

Update (2026-07-14)

  • Rebased onto main after fix: unblock fresh deploys (AWS CDK CLI pin + auth-ui asset upload) #10 — the fresh-deploy fixes now land separately.
  • x86_64 support added: weighted Karpenter NodePools — arm64 (AWS Graviton,
    weight 100, preferred) + amd64 fallback (weight 10) — sharing one
    arch-agnostic EC2NodeClass (userData resolves the gVisor binary via
    $(uname -m); the tenant image is published multi-arch).
  • RuntimeClass overhead.podFixed (128Mi/50m) so the scheduler and
    Karpenter account for the per-pod gVisor Sentry.
  • ADR-0007 extended: mechanism honesty table (what each isolation layer
    stops / does not stop), a runtime tier extension contract (the four seams
    any future runtime tier plugs into: RuntimeClass, NodePool+NodeClass, the
    sandbox.runtimeClassName Helm value, and a conformance pass), and a tier
    policy (at most two runtime tiers; a new hardened tier replaces the previous
    one).
  • scripts/conformance-runtime-tier.sh: codifies the four-point E2E gate
    (kernel identity, Amazon EKS Pod Identity reachability, Amazon EFS RWX write,
    Amazon Bedrock endpoint reachability) required by the extension contract.

@snese
snese marked this pull request as ready for review June 25, 2026 10:06
snese added 6 commits July 14, 2026 14:52
RuntimeClass gvisor (handler runsc) + dedicated tainted gVisor EC2NodeClass
(AL2023 ARM64, runsc shim via user-data, containerd v2 io.containerd.cri.v1
runtime path) + gVisor NodePool (arm64, taint openclaw/runtime=gvisor, label
in requirements). Verified in a live spike: Pod Identity works under gVisor,
so the tenant IAM model is unchanged. Part of #5.
…se 2)

When sandbox.runtimeClassName=gvisor, the per-tenant SandboxTemplate sets
runtimeClassName and tolerates the gVisor NodePool taint (RuntimeClass
scheduling also injects nodeSelector+toleration). Document the value and add
a third helm-lint variant for the gvisor tier. Part of #5.
…sion contract

- Weighted NodePools: arm64 (Graviton, weight 100, preferred) + amd64
  fallback (weight 10) sharing one arch-agnostic EC2NodeClass (userData
  resolves runsc via uname -m; tenant image is multi-arch).
- RuntimeClass overhead.podFixed (128Mi/50m) so scheduler + Karpenter
  account for the per-pod gVisor Sentry.
- ADR-0007: mechanism honesty table (what each isolation layer stops and
  does not stop), runtime tier extension contract (4 seams), tier policy
  (at most two tiers; new hardened tiers replace, not accumulate).
- scripts/conformance-runtime-tier.sh: codifies the 4-point E2E gate
  (kernel identity, Pod Identity, EFS RWX, Bedrock reachability) required
  by the extension contract.
@snese
snese force-pushed the feat/gvisor-runtime-tier branch from 4d3b3f7 to f16d822 Compare July 14, 2026 06:52
@snese snese changed the title feat(gvisor): gVisor runtime tier (PR#2) — WIP feat(gvisor): selectable gVisor runtime tier for tenant sandboxes Jul 14, 2026
…eal conformance gates

- Pin gVisor to dated release 20260706 with sha512 verification and
  curl --retry 3 (was: unpinned 'latest', no checksum).
- Drop platform=ptrace from runsc.toml: runsc defaults to systrap;
  ptrace is deprecated upstream.
- Move maxPods to EC2NodeClass spec.kubelet so Karpenter accounts for
  it in node capacity (was: raw userData NodeConfig, invisible to
  Karpenter).
- Conformance: Pod Identity check now performs an AUTHENTICATED
  credential fetch (token from AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE)
  and asserts AccessKeyId — previously an unauthenticated 401 could
  never fail the pipe-masked check. Bedrock check renamed to honest
  reachability semantics (2xx-4xx = reached; timeouts fail).
- Remove dead scheduling_fields variable.
@snese

snese commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Review + live verification complete (2026-07-14).

Multi-agent review verdict: MERGE-AFTER-FIXES — all 5 blockers addressed in the latest commits (pinned runsc 20260706 + sha512 verify + retry; systrap default; authenticated Pod Identity conformance gate; honest Bedrock reachability semantics; kubelet maxPods moved to EC2NodeClass).

Live E2E on a CDK-updated cluster (UPDATE_COMPLETE), post-fix:

  • Fresh gVisor node bootstrapped with the pinned, checksum-verified runsc under systrap (default platform): /proc/version = Linux 4.19.0-gvisor
  • scripts/conformance-runtime-tier.sh gvisor: 4/4 PASS (gVisor kernel, authenticated Pod Identity credential fetch via real association, EFS RWX, Bedrock endpoint reachability HTTP 403)
  • scripts/conformance-runtime-tier.sh "" (runc baseline): PASS
  • amd64 fallback pool verified earlier today: Karpenter provisioned x86_64 node, gVisor kernel confirmed

Merging.

@snese
snese merged commit c8d2a90 into main Jul 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant