feat(kustomize): add OpenShift components for the restricted-v2 SCC and Routes - #51
Open
pratapalakshmi wants to merge 2 commits into
Open
feat(kustomize): add OpenShift components for the restricted-v2 SCC and Routes#51pratapalakshmi wants to merge 2 commits into
pratapalakshmi wants to merge 2 commits into
Conversation
…nd Routes OpenShift ignores the image's USER, assigns an arbitrary UID from the namespace's range, and validates the pod's own request with MustRunAsRange -- so the nonroot-security-context component, which pins runAsUser/runAsGroup/fsGroup 1000, is rejected at admission and prevents every pod from scheduling. Neither ingress component produces anything the OpenShift router serves either. Two new components, both drop-in replacements rather than changes to existing behaviour: - openshift-security-context: the same hardening as nonroot-security-context (runAsNonRoot, capabilities.drop ALL, seccompProfile RuntimeDefault) with no UID named, so the SCC assigns one. As with nonroot-security-context, the bundled datastores are not patched -- they are listed after it in the overlay and cannot run under an arbitrary UID anyway. - ingress-openshift: removes the base nginx Ingress (inert on OpenShift) and adds one route.openshift.io/v1 Route per path, mirroring base/ingress.yaml. Each carries haproxy.router.openshift.io/timeout, because the router's 30s default severs /live/ WebSockets and /pi/ streaming. Declaring the Routes avoids depending on whether annotations survive the ingress-to-route conversion, which varies by OCP version. The component carries its own APP_DOMAIN replacement, so enabling it is the only overlay change needed. Verified by building the default overlay with both components swapped in: 11 Routes with the host replacement applied, the base Ingress gone, and no workload requesting a fixed uid/gid except the bundled opensearch -- which behaves identically under nonroot-security-context, so this is not a regression. Nothing existing changes: both are new opt-in components, and no shared file other than the README is touched. Requires the images from plane-ee #9018, which grant group 0 write access to the paths they write at runtime. Chart equivalent: helm-charts #<pending>. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The two components alone left every operator to assemble the overlay themselves,
and the obvious move -- copy `default` and toggle components -- does not work:
`default` pins runAsUser 1000 and ships the in-cluster datastores, and OpenShift
rejects both. This adds the assembled overlay so there is a real starting point.
overlays/openshift is `default` with exactly three differences:
- openshift-security-context instead of nonroot-security-context (no UID named,
because restricted-v2 assigns one and rejects a pod that asks for a specific
runAsUser/runAsGroup/fsGroup)
- ingress-openshift instead of ingress-nginx (base Ingress removed, 11 Routes
added, each with haproxy.router.openshift.io/timeout: 300s)
- postgres/redis/rabbitmq/minio/opensearch omitted -- third-party images with
baked-in UID and data-directory ownership that cannot run under an arbitrary
UID, so the overlay expects external services
Consequently the storage-class patches (which only ever targeted those five
StatefulSets) are gone, as are the two replacements targeting kind: Ingress --
ingress-openshift carries its own APP_DOMAIN -> Route spec.host replacement.
static-db-url and s3-static-credentials ARE kept. They are about static
credentials vs a cloud workload identity, not about in-cluster vs external:
static-db-url is the only thing that populates plane-silo-secrets.DATABASE_URL,
and s3-static-credentials the only thing that populates the doc-store AWS keys.
Dropping them silently leaves silo without a database and S3 unauthenticated.
vars.yaml.example drops INGRESS_CLASS (Routes carry no class) and defaults
MONITOR_STORAGE_CLASS to gp3-csi rather than the EKS-only gp2.
secrets-vars.yaml.example points every connection string at an external service
and sets USE_MINIO=0.
Verified with `kustomize build`: 11 Routes on the APP_DOMAIN host, 0 Ingress
objects, namespace plane-openshift, no workload requesting a fixed uid/gid,
plane-monitor the only StatefulSet, MONITOR_STORAGE_CLASS flowing through to its
PVC, and DATABASE_URL/AWS keys populated in the app, silo and doc-store secrets.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Kustomize counterpart to plane-ee#9018 (images) and helm-charts#289 (chart).
OpenShift ignores the image's
USER, assigns an arbitrary UID from the namespace's range, and validates the pod's own request withMustRunAsRange— sononroot-security-context, which pinsrunAsUser/runAsGroup/fsGroup: 1000, is rejected at admission and stops every pod from scheduling. Neither ingress component produces anything the OpenShift router serves either.Two new opt-in components. Nothing existing changes; no shared file other than the README is touched.
openshift-security-contextnonroot-security-context—runAsNonRoot,capabilities.drop: [ALL],seccompProfile: RuntimeDefault— with no UID named, so the SCC assigns one.ingress-openshiftIngress(inert on OpenShift) and adds oneroute.openshift.io/v1Route per path, mirroringbase/ingress.yaml. Each carrieshaproxy.router.openshift.io/timeout: 300s— the router's 30s default severs/live/WebSockets and/pi/streaming. Ships its ownAPP_DOMAINreplacement, so enabling it is the only overlay change needed.Verification
Built the
defaultoverlay with both components swapped in fornonroot-security-context:plane.example.com→ the overlay'sAPP_DOMAIN)Ingressremovedplane-opensearchThat opensearch exception is not a regression — I built the same overlay with
nonroot-security-contextand it keepsfsGroup: 1000/runAsUser: 1000identically. The datastore components (postgres,redis,rabbitmq,minio,opensearch) are listed after the security-context component in the overlay, so neither component ever patches them. They cannot run under an arbitrary UID regardless, which is why the README says to drop them on OpenShift and use managed services.Why explicit Routes rather than ingress-to-route
Keeping the base
Ingressand settingINGRESS_CLASS: "openshift-default"also works — the README documents it as the alternative. But the conversion only picks up anIngresswhose class maps toopenshift.io/ingress-to-route(nginxis ignored), and whether the per-route HAProxy annotations survive varies by OCP version. Plane needs that timeout, so declaring the Routes removes the guesswork.Routes have no request-body cap — Traefik's
plane-body-limitmiddleware has no equivalent. Path rewriting (e.g. thedraw-iocomponent'sstripPrefix) needshaproxy.router.openshift.io/rewrite-targetinstead, and Traefik'sredirectRegexhas no Route equivalent at all. Both are called out in the component header and README.Requires
The images from plane-ee#9018, which grant group 0 write access to their runtime paths. Those have been validated on a real cluster under an arbitrary UID — see internal-scripts#122. SCC admission and Route behaviour still need a CRC / OpenShift Local run.
🤖 Generated with Claude Code