diff --git a/deploy/helm/openshell/README.md b/deploy/helm/openshell/README.md index 436a4b5d2..fcb7a108e 100644 --- a/deploy/helm/openshell/README.md +++ b/deploy/helm/openshell/README.md @@ -585,6 +585,11 @@ discovery endpoint or its TLS CA. | supervisor.image.registry | string | `""` | Supervisor image registry. Empty uses global.image.registry. | | supervisor.image.repository | string | `"openshell/supervisor"` | Supervisor image repository. | | supervisor.image.tag | string | `""` | Supervisor image tag. Defaults to the chart appVersion when empty. | +| supervisor.podSecurityContext.fsGroup | int | `65534` | fsGroup assigned to the shared supervisor pod. | +| supervisor.podSecurityContext.runAsGroup | int | `65534` | Primary GID assigned to the shared supervisor pod. | +| supervisor.podSecurityContext.runAsNonRoot | bool | `true` | Require the shared supervisor to run as a non-root user. | +| supervisor.podSecurityContext.runAsUser | int | `65534` | UID assigned to the shared supervisor pod. | +| supervisor.podSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` | Seccomp profile applied to the shared supervisor pod. | | supervisor.sandboxRuntime.boundaryPort | int | `5500` | Workload boundary TLS listener port. | | tolerations | list | `[]` | Tolerations for the gateway pod. | | upstreamProxy | object | `{"authAllowInsecure":false,"authSecret":{"key":"","name":""},"caBundle":{"configMapName":"","key":"ca.crt"},"connectByHostname":false,"noProxy":"","url":""}` | Operator-owned corporate forward proxy for policy-approved TLS egress from Kubernetes sandboxes. The workload cannot select or override it. | diff --git a/deploy/helm/openshell/ci/values-openshift-scc.yaml b/deploy/helm/openshell/ci/values-openshift-scc.yaml index b7f37be6e..4b0690465 100644 --- a/deploy/helm/openshell/ci/values-openshift-scc.yaml +++ b/deploy/helm/openshell/ci/values-openshift-scc.yaml @@ -18,3 +18,11 @@ securityContext: capabilities: drop: - ALL + +# The shared supervisor keeps runAsNonRoot and its seccomp profile; the SCC +# assigns its user, group, and fsGroup IDs. +supervisor: + podSecurityContext: + runAsUser: null + runAsGroup: null + fsGroup: null diff --git a/deploy/helm/openshell/templates/supervisor.yaml b/deploy/helm/openshell/templates/supervisor.yaml index 9d5c695cf..c31fbb610 100644 --- a/deploy/helm/openshell/templates/supervisor.yaml +++ b/deploy/helm/openshell/templates/supervisor.yaml @@ -39,13 +39,10 @@ spec: - name: {{ . | quote }} {{- end }} {{- end }} + {{- with .Values.supervisor.podSecurityContext }} securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - fsGroup: 65534 - seccompProfile: - type: RuntimeDefault + {{- toYaml . | nindent 8 }} + {{- end }} containers: - name: supervisor image: {{ get $kubernetes "supervisor_image" | quote }} diff --git a/deploy/helm/openshell/values.yaml b/deploy/helm/openshell/values.yaml index b1b4e3ded..04fc1152a 100644 --- a/deploy/helm/openshell/values.yaml +++ b/deploy/helm/openshell/values.yaml @@ -69,6 +69,22 @@ supervisor: tag: "" # -- Supervisor image digest. When set, this takes precedence over tag. digest: "" + # Pod security context for the shared supervisor Deployment, rendered only + # when gatewayConfig selects supervisor_topology = "gateway". On OpenShift, + # set the user and group IDs to null so the restricted-v2 SCC can assign the + # namespace range; ci/values-openshift-scc.yaml does this. + podSecurityContext: + # -- Require the shared supervisor to run as a non-root user. + runAsNonRoot: true + # -- UID assigned to the shared supervisor pod. + runAsUser: 65534 + # -- Primary GID assigned to the shared supervisor pod. + runAsGroup: 65534 + # -- fsGroup assigned to the shared supervisor pod. + fsGroup: 65534 + seccompProfile: + # -- Seccomp profile applied to the shared supervisor pod. + type: RuntimeDefault sandboxRuntime: # -- Workload boundary TLS listener port. boundaryPort: 5500 diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 0c0a39ee2..1dab79be8 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -1279,6 +1279,7 @@ credential failures. | One replica holds most sessions after a rollout | Expected: sessions stay where they reconnected | `openshell_server_supervisor_sessions` per pod; it fades as sandboxes are recreated | | Gateway or `-certgen` hook pod rejected with `violates PodSecurity "restricted:latest"` | The rendered container lacks `runAsNonRoot` or `seccompProfile`: an older chart version does not set them, or an override in `securityContext` / `pkiInitJob.securityContext` unset them | `kubectl -n openshell get events --field-selector reason=FailedCreate`; upgrade the chart, then remove overrides that unset those fields | | OpenShift gateway pod fails to start with an SCC/`runAsUser` error (e.g. `unable to validate against any security context constraint`) | Chart's default `podSecurityContext`/`securityContext` hardcodes `runAsUser`/`fsGroup`, which the restricted-v2 SCC rejects; it must instead inject the namespace-assigned UID/GID range | `oc -n openshell describe pod `; deploy with `podSecurityContext: null` and clear `securityContext.runAsUser` (see `deploy/helm/openshell/ci/values-openshift-scc.yaml`) | +| OpenShift `-supervisor` Deployment never creates pods after setting `supervisor_topology = "gateway"` (SCC `runAsUser`/`fsGroup` not in the namespace range) | `supervisor.podSecurityContext` defaults `runAsUser`, `runAsGroup`, and `fsGroup` to 65534, outside the namespace's assigned UID/GID ranges | `kubectl -n openshell get events --field-selector reason=FailedCreate`; compare with the `openshift.io/sa.scc.*` annotations from `oc describe ns openshell`; set `supervisor.podSecurityContext.runAsUser`, `.runAsGroup`, and `.fsGroup` to `null`, as `deploy/helm/openshell/ci/values-openshift-scc.yaml` does, and keep `runAsNonRoot` and `seccompProfile` | | OpenShift sandbox pod fails to start (`unable to validate against any security context constraint`) | The `openshell-sandbox` service account lacks the privileged SCC it needs | `oc adm policy add-scc-to-user privileged -z openshell-sandbox -n openshell`; remove with `remove-scc-from-user` when done | | OpenShift self-hosted Vault/OpenBao credential store pod never schedules (waits time out with `no matching resources found`) | The store's Helm chart pins `runAsUser`/`fsGroup`/seccomp, which restricted-v2 rejects, so the StatefulSet controller never creates the pod | Deploy the store's chart in its OpenShift mode (`--set global.openshift=true` for the OpenBao/Vault chart) so the namespace SCC assigns a compliant security context — no manual SCC grant needed | | Vault credential driver returns HTTP 403 / `Vault Kubernetes auth denied the configured role` on provider create | Vault's `auth/kubernetes` method or the gateway login role is not provisioned, or the role is not bound to the gateway service account and namespace | In Vault: `bao auth enable kubernetes` and `bao write auth/kubernetes/config kubernetes_host=... kubernetes_ca_cert=@...`; ensure the login role's `bound_service_account_names`/`bound_service_account_namespaces` match the gateway SA and namespace and its policy grants the credential paths |