Skip to content

Commit 99d40f0

Browse files
committed
feat(supervisor): configurable security context for run pods
1 parent 2496a8a commit 99d40f0

4 files changed

Lines changed: 44 additions & 0 deletions

File tree

apps/supervisor/src/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ export const Env = z
220220
KUBERNETES_RUNNER_SECCOMP_PROFILE_RUNTIMES: z
221221
.enum(["none", "node-24-plus", "all"])
222222
.default("node-24-plus"),
223+
KUBERNETES_RUNNER_SECURITY_CONTEXT: z.enum(["off", "baseline", "restricted"]).default("off"),
223224

224225
// Pod DNS config — override the cluster default ndots to `KUBERNETES_POD_DNS_NDOTS`.
225226
// Default k8s ndots is 5: any name with fewer than 5 dots (e.g. `api.example.com`, 2 dots) is first walked

apps/supervisor/src/workloadManager/kubernetes.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
22
import {
33
nodetypeNodeSelector,
44
runPodTolerations,
5+
runnerSecurityContext,
56
withRunnerSeccompProfile,
67
withNodeSelector,
78
} from "./kubernetesPodSpec.js";
@@ -153,3 +154,24 @@ describe("withRunnerSeccompProfile", () => {
153154
}
154155
});
155156
});
157+
158+
describe("runnerSecurityContext", () => {
159+
it("sets nothing when off", () => {
160+
expect(runnerSecurityContext("off")).toBeUndefined();
161+
});
162+
163+
it("drops all capabilities and blocks escalation at baseline", () => {
164+
expect(runnerSecurityContext("baseline")).toEqual({
165+
allowPrivilegeEscalation: false,
166+
capabilities: { drop: ["ALL"] },
167+
});
168+
});
169+
170+
it("additionally requires a non-root image when restricted", () => {
171+
expect(runnerSecurityContext("restricted")).toEqual({
172+
allowPrivilegeEscalation: false,
173+
capabilities: { drop: ["ALL"] },
174+
runAsNonRoot: true,
175+
});
176+
});
177+
});

apps/supervisor/src/workloadManager/kubernetes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { getRunnerId } from "../util.js";
1717
import {
1818
nodetypeNodeSelector,
1919
runPodTolerations,
20+
runnerSecurityContext,
2021
withRunnerSeccompProfile,
2122
withNodeSelector,
2223
} from "./kubernetesPodSpec.js";
@@ -175,6 +176,7 @@ export class KubernetesWorkloadManager implements WorkloadManager {
175176
},
176177
],
177178
resources: this.#getResourcesForMachine(opts.machine),
179+
securityContext: runnerSecurityContext(env.KUBERNETES_RUNNER_SECURITY_CONTEXT),
178180
env: [
179181
{
180182
name: "TRIGGER_DEQUEUED_AT_MS",

apps/supervisor/src/workloadManager/kubernetesPodSpec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,22 @@ export function withRunnerSeccompProfile(
9696
},
9797
};
9898
}
99+
100+
/**
101+
* runnerSecurityContext maps a configured level onto the run container's security
102+
* context. "baseline" drops the capability bounding set and blocks setuid
103+
* escalation; "restricted" additionally requires a non-root image.
104+
*/
105+
export function runnerSecurityContext(
106+
level: "off" | "baseline" | "restricted"
107+
): k8s.V1SecurityContext | undefined {
108+
if (level === "off") {
109+
return undefined;
110+
}
111+
112+
return {
113+
allowPrivilegeEscalation: false,
114+
capabilities: { drop: ["ALL"] },
115+
...(level === "restricted" ? { runAsNonRoot: true } : {}),
116+
};
117+
}

0 commit comments

Comments
 (0)