Repository navigation
fix(helm): render Restricted-compatible security contexts - #3340
lunarwhite wants to merge 1 commit into
Conversation
6ade663 to
4b1ecf9
Compare
24d0027 to
fe256da
Compare
0dae16d to
b50de7d
Compare
|
Hi @johntmyers, would you please add this to your review queue? It's part of the 0.1.15 milestone. Thanks. |
|
Hi @TaylorMutch (it's really great to see you're back! I hope everything went well), would you be interested in reviewing this PR? |
|
Label |
|
/ok to test b50de7d |
|
@lunarwhite can you rebase on top of main to see if we can get past the E2E flakes? |
Signed-off-by: Yuedong Wu <dwcn22@outlook.com>
b50de7d to
0163cdc
Compare
|
/ok to test 0163cdc |
Compatibility review (advisory)Unaddressed breaking changes The certgen hook now requires non-root execution by default. Existing releases using a root-based custom gateway image can fail during install or upgrade unless they add a new override. 1. helm — NOT ACKEDThe certgen hooks previously accepted the image’s root user but now set
Review details
Advisory review; publication gates are unchanged. |
Summary
Pod Security admission rejects the certgen hook in a namespace enforcing Restricted, blocking the whole release at
helm.sh/hook-weight: "-20". This adds the missing controls to both certgen Jobs and to the gateway container, and makes the hook context overridable.Related Issue
Closes #3215
Changes
templates/certgen.yaml: addrunAsNonRootandseccompProfile.type: RuntimeDefaultto the hook container, rendered from values rather than hardcoded. Apply the same context to the-backend-capost-install hook.values.yaml: addseccompProfile.type: RuntimeDefaultto the gatewaysecurityContext; addpkiInitJob.securityContext, defaulted to what the hook previously hardcoded.tests/certgen_test.yaml,tests/gateway_pod_security_context_test.yaml: assert the Restricted controls on all three containers, and that the certgen hook sets norunAsUser.docs/kubernetes/setup.mdx: Pod Security section.skills/debug-openshell-cluster/SKILL.md: troubleshooting row for the PodSecurity rejection.README.md: regenerated.Design notes
The gateway was broken too, and the hook was hiding it. The hook fails first at weight
-20, so the gateway's own missingseccompProfilenever surfaced. A hook-only fix would leave the release recorded as deployed while the workload never comes up.Both certgen Jobs are covered.
<release>-certgen-backend-ca, the post-install hook that renders when cert-manager andgrpcRoute.backendTLSPolicyare both enabled, had the identical gap. Both Jobs now render from onepkiInitJob.securityContext, so the two cannot drift again, which is what caused this bug.Field placement is load-bearing.
allowPrivilegeEscalationandcapabilities.drophave no pod-level equivalent, so all four controls live together on the container. The gateway profile must be onsecurityContextrather thanpodSecurityContextbecauseci/values-openshift-scc.yamlnulls the pod block.runAsUserstays unset on the hook:Dockerfile.gatewaydeclares a numericUSER 1000:1000, which is what kubelet needs to admitrunAsNonRootwithout an explicit UID, and setting one would break OpenShift restricted-v2, which assigns the namespace UID itself. AnotExistsassertion pins that.Container-level override only. This satisfies acceptance criterion 3, which is conditional ("if operators need to override"). No pod-level knob is added: the hook pods run one container and mount no volumes, so the pod-scoped fields have nothing to act on. The gateway has
podSecurityContextonly because its StatefulSet mounts a PVC. Defaults are unchanged, so no existing install is affected.Scope
This covers the chart's own pods: the gateway and both certgen hooks. Sandbox pods come from the Kubernetes compute driver, not the chart. Under the current sandbox architecture they are capability-free and non-root, but RFC 0012 does not guarantee Pod Security Standards compliance, so the docs make no claim about them.
Known risks
helm upgraderolls the gateway and applies the CRI syscall filter to a process that previously ran unconfined on most clusters. The gateway does no mount, namespace, or bpf work, and e2e installs chart defaults on every run.pkiInitJob.securityContext: nullrenders an empty context and silently reverts the fix. This matches how_gateway-workload.tplalready treats.Values.securityContext, so it is consistent with the existing pattern rather than a new failure mode.Testing
mise run pre-commitpassesTests added (unit only; chart rendering has no integration layer, and no
e2e/files changed): the four Restricted controls on the certgen hook and the gateway container,runAsNonRootandseccompProfile.typeon the backend CA hook, andnotExistson the certgen hook'srunAsUser.Each was confirmed to fail without the template change:
Admission verification
kindv0.32.0, Kubernetes v1.36.1 (the report is v1.36.4), namespace labeledpod-security.kubernetes.io/enforce=restrictedandenforce-version=latest. PodSecurity enforces on Pods rather than on the workloads that create them, so each rendered pod template was submitted as a bare Pod withkubectl apply --dry-run=server.Before, both pods are rejected, reproducing the report and exposing the masked gateway failure:
After, both are admitted and the workloads emit no warnings:
The hook then ran for real in the Restricted namespace, completing in 17s and creating all three PKI secrets:
All
ci/values-*.yamloverlays, plus thebackendTLSPolicy, upstream proxy CA, SPIFFE, and Deployment combinations, were checked against the full Baseline and Restricted rule set, including volume types, host namespaces, and host ports. Every rendered container pass, includingvalues-openshift-scc, where the overlay keepsseccompProfileand dropsrunAsUserunder Helm's deep merge. Onmainwithout this change, the same check flags only the hook and gateway gaps fixed here.Seccomp on the long-running gateway
RuntimeDefaultnewly applies the runtime's syscall filter to the gateway, so it was exercised rather than argued.mise run e2e:kubernetesonkindv1.36.1 withghcr.io/nvidia/openshell/gateway:dev:The gateway reached Ready under
RuntimeDefault, bound all three listeners, provisioned its SQLite PVC, and servedCreateSandbox,ListSandboxes,GetSandbox, andDeleteSandboxwith HTTP 200 across a seven-minute reconcile window.The suite does not pass end to end on that host:
smoke/createtimes out withDependenciesNotReady: Pod exists with phase: Failed. That is a sandbox-pod failure, pre-existing and unrelated, the same lane at the base commit produces the byte-identical diagnostic. Sandbox pods are built by the Kubernetes compute driver at runtime, and.Values.securityContexthas exactly one consumer,_gateway-workload.tpl, so this change cannot reach them.Checklist