Post-1.0: Localhost seccomp on K8s, warm sandbox pool, server HPA
- K8sDriver.with_localhost_seccomp(profile): sandbox pods run under the STRICT allowlist instead of the runtime default. Proven live on kind: the harness installs the profile onto the node, a pod runs ordinary work as uid 10001, and unshare is kernel-denied inside the pod — the same probe the Docker suite uses, now passing on both targets - Helm: sandbox.seccomp=localhost renders a DaemonSet that installs the chart-shipped profile into /var/lib/kubelet/seccomp on every node (ConfigMap + hostPath); ci/check-helm.sh enforces the chart copy stays byte-identical to images/seccomp/agent-profile.json and asserts the hardened render (DaemonSet + profile + HPA) - server HPA (autoscaling/v2, CPU target) behind server.autoscaling.enabled - SandboxManager.warm(n): a background warmer keeps n pre-provisioned sandboxes ready so an agent's first exec skips container startup; unhealthy pool entries are discarded, reuse never drains the pool, shutdown destroys assigned AND pooled. [sandbox] warm_pool config (default 0). Real-Docker test: prefill -> assign -> refill -> reuse -> clean shutdown 160 Rust tests + 4 live kind tests. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a26939d7bc
commit
05e9612688
@@ -145,3 +145,60 @@ async fn destroy_removes_the_pod_and_health_reflects_it() {
|
||||
}
|
||||
panic!("pod never disappeared");
|
||||
}
|
||||
|
||||
/// With the strict allowlist installed on the node (the Helm DaemonSet's
|
||||
/// job; the harness drops it into the kind node), pods run under
|
||||
/// `Localhost` seccomp and the kernel refuses what the profile removed.
|
||||
#[tokio::test]
|
||||
async fn localhost_seccomp_profile_denies_unshare_inside_pods() {
|
||||
ensure_image_in_kind();
|
||||
let status = Command::new("docker")
|
||||
.args([
|
||||
"exec",
|
||||
"teamclaw-test-control-plane",
|
||||
"mkdir",
|
||||
"-p",
|
||||
"/var/lib/kubelet/seccomp",
|
||||
])
|
||||
.status()
|
||||
.expect("kind node reachable");
|
||||
assert!(status.success());
|
||||
let root = env!("CARGO_MANIFEST_DIR");
|
||||
let status = Command::new("docker")
|
||||
.args([
|
||||
"cp",
|
||||
&format!("{root}/../../images/seccomp/agent-profile.json"),
|
||||
"teamclaw-test-control-plane:/var/lib/kubelet/seccomp/teamclaw-agent-profile.json",
|
||||
])
|
||||
.status()
|
||||
.expect("docker cp");
|
||||
assert!(status.success());
|
||||
|
||||
let driver = K8sDriver::connect(NAMESPACE)
|
||||
.await
|
||||
.expect("cluster reachable")
|
||||
.with_localhost_seccomp("teamclaw-agent-profile.json");
|
||||
let spec = SandboxSpec {
|
||||
name: format!("tc-k8s-seccomp-{}", std::process::id()),
|
||||
image: IMAGE.into(),
|
||||
memory_bytes: 256 * 1024 * 1024,
|
||||
nano_cpus: 1_000_000_000,
|
||||
pids_limit: 128,
|
||||
egress: false,
|
||||
};
|
||||
let handle = driver.provision(&spec).await.expect("pod provisions");
|
||||
|
||||
// Ordinary work runs...
|
||||
let ok = driver.exec(&handle, &["id", "-u"]).await.unwrap();
|
||||
assert_eq!(ok.stdout.trim(), "10001");
|
||||
|
||||
// ...but the syscalls stripped from the allowlist are gone — the
|
||||
// same kernel probe the Docker suite uses.
|
||||
let unshare = driver
|
||||
.exec(&handle, &["unshare", "--user", "true"])
|
||||
.await
|
||||
.unwrap();
|
||||
assert_ne!(unshare.exit_code, 0, "unshare must be denied: {unshare:?}");
|
||||
|
||||
driver.destroy(&handle).await.unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user