Skip to content

OpenShift & OKD — Self-Hosted Installation

RunWhen Platform installs on OpenShift and OKD using the same Helm chart as any other Kubernetes distribution. The functional differences at deploy time all trace back to one thing: OpenShift enforces Security Context Constraints (SCCs) at admission. A few chart components — most importantly the bundled Postgres image (Spilo) and Vault’s Kubernetes auth — require actions that the namespace / project owner cannot perform on their own.

This page is written for the cluster administrator (or platform / security engineer) who has to sign off on those actions. The goal is to explain, in plain terms, what is being asked for, why each ask is necessary for the platform to run, and why granting it does not weaken your cluster’s security posture. Once these one-time actions are in place, the application team can install and upgrade RunWhen from inside a single namespace with no cluster-scoped permissions.

If you are the person running helm install, read Self-Hosted Deployment Requirements for the shared prerequisites (registry, DNS, TLS, LLM), then come back here for the OpenShift-specific pieces.


The short version

There are exactly three cluster-admin actions you will be asked to take once, before the namespace owner runs Helm:

#ActionScopeReversible?
1Create an image pull secret in the install namespaceOne namespace, one SecretDelete the Secret
2Grant the anyuid SCC to one ServiceAccount ({release}-postgresql)One ServiceAccount in one namespaceoc adm policy remove-scc-from-user
3Create one ClusterRoleBinding for Vault’s token-review call (system:auth-delegator)One SA can call TokenReviewkubectl delete clusterrolebinding
4(Recommended) Apply ResourceQuota and LimitRange for the install namespace, or bake into ProjectRequestTemplateOne namespace or cluster-wideDelete the quota / template

Everything else the chart installs — UI, PAPI, AgentFarm, search, LLM gateway, object store — runs as an arbitrary non-root UID under stock restricted, with read-only root filesystems, dropped capabilities, and the runtime default seccomp profile. The Postgres exception and the Vault binding are the only two places the chart cannot fit inside a stock namespace-scoped install.

If your policy forbids anyuid entirely, you have two alternatives:

  • Custom SCC — allow only UID 101 (Spilo’s baked-in user), bound only to {release}-postgresql. This is a stricter, allow-listed version of the same exception.
  • External Postgres — set postgresql.kind: external and point the chart at a database you already run. Skips both the SCC exception and the Vault-adjacent chart Postgres entirely.

Details, YAML, and the reasoning behind each choice are below.


Why OpenShift needs a different conversation

Vanilla Kubernetes enforces workload identity through Pod Security Standards (Baseline / Restricted) and whatever admission webhook you layer on top. Chart defaults that pin runAsUser: 1000 satisfy Restricted because the standard only says “non-root” — any non-zero UID is fine.

OpenShift is stricter by design. It assigns each project a UID range — for example 1000810000/10000 — and its default SCC (restricted-v2) rejects any pod that pins a UID outside that range, even a normal non-root value like 1000. The philosophy is straightforward: no two projects should be able to run as the same UID, so a container-escape or shared-volume mistake in one namespace cannot masquerade as another.

That model works well when an image is built to accept whatever UID it is handed. It struggles with images that hard-code a UID at build time — because their entrypoint expects specific /etc/passwd entries, chowns files to a known owner, or writes to paths owned by a fixed group. Those images cannot simply run as 1000817342 and hope for the best.

RunWhen first-party images are built to accept any non-root UID; they will run cleanly under stock restricted. Bundled Spilo is not: it expects UID 101 and fsGroup 103 because that is how the upstream Zalando image is baked. When OpenShift admission hands Spilo a random project UID, its bootstrap chown calls fail (Operation not permitted) and the pod crash-loops before Postgres ever starts.

You have four ways to reconcile that mismatch, and the rest of this page walks through them.


The four options, and when each one is appropriate

OptionWhat it doesStays on stock restricted?Best fit
A — Strict restrictedChart values null every fixed UID; everything runs as the project’s assigned UIDYes, for workloads that admitFirst choice; everything except Spilo works
B — Scoped anyuid for PostgresRestore Spilo’s UID 101, grant anyuid only to {release}-postgresqlNo — one ServiceAccount onlyRecommended default for bundled Postgres
C — Custom SCC (UID 101 allow-list)Cluster-admin defines an SCC that permits only UID 101; bind it to {release}-postgresqlPartial (not stock restricted, but narrower than anyuid)Enterprises that forbid anyuid outright
D — External Postgrespostgresql.kind: external; you run Postgres elsewhereYesYou already operate a Postgres you trust — see External PostgreSQL

Everything that follows assumes Option A for the general fleet plus Option B (or C, or D) for Postgres. Redis, Neo4j, and Vault are optional exceptions only if Option A hits a runtime problem in your cluster — we will get to those at the end.


What the cluster admin actually grants — and why it is safe

The two SCC/RBAC actions you will sign off on are narrower than they sound. This section is deliberately explicit about what changes and what does not.

1. anyuid for the Postgres ServiceAccount

What the ask is. Bind the built-in system:openshift:scc:anyuid ClusterRole to exactly one ServiceAccount — {release}-postgresql — inside the RunWhen namespace. Nothing else in the namespace gains this ability.

What anyuid actually relaxes. Compared to restricted-v2, anyuid differs in one dimension: pods bound to it may pin a specific UID instead of accepting one from the project range. Everything else still applies:

  • Pods still run non-root (Spilo runs as UID 101, not 0)
  • Root filesystem is still read-only where the chart sets it
  • Linux capabilities are still dropped (drop: ["ALL"], add: [])
  • No hostNetwork, hostPID, hostIPC, or privileged containers
  • No hostPath volumes
  • No new access to the API server, no new RBAC, no new secrets

The one wrinkle: stock OpenShift anyuid has Allowed Seccomp Profiles: <none> — it will refuse the pod entirely if seccompProfile: RuntimeDefault is set. The overlay clears that field on the Spilo pod, which sounds worse than it is: with capabilities dropped, no hostPath, no privilege escalation, and a fixed unprivileged UID, the seccomp filter was already the weakest defense in the stack for this specific pod. If your policy requires seccomp, use Option C (custom SCC) and add Allowed Seccomp Profiles: runtime/default — otherwise this is a normal accepted trade-off in OpenShift Postgres installs.

Why this is a standard OpenShift pattern. Red Hat documents oc adm policy add-scc-to-user anyuid -z <sa> as the recommended way to run community images that expect a specific UID — the same fix is used for Bitnami charts, MinIO, JupyterHub, upstream Grafana, and most vendor-provided Postgres/Redis operators. It is not a workaround; it is the sanctioned path for images that predate OpenShift’s random-UID model.

Blast radius. A single ServiceAccount in a single namespace. Any pod that does not use that ServiceAccount — including everything else RunWhen installs — still admits through restricted unchanged. You can audit the exception with:

Terminal window
oc get rolebindings,clusterrolebindings --all-namespaces \
-o jsonpath='{range .items[?(@.roleRef.name=="system:openshift:scc:anyuid")]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'

Apply it. Use oc adm policy for a quick grant, or apply the RoleBinding YAML so the exception lives in git alongside your other cluster configuration:

Terminal window
export NS=runwhen-platform
export RELEASE=rw
oc adm policy add-scc-to-user anyuid \
-z "${RELEASE}-postgresql" -n "$NS"
Show the equivalent RoleBinding YAML

The chart ships this manifest at charts/runwhen-platform/manifests/openshift/rw-postgresql-anyuid.rolebinding.yaml so the exception is reviewable in a pull request instead of living only in shell history.

rw-postgresql-anyuid.rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: system:openshift:scc:anyuid
namespace: runwhen-platform
labels:
app.kubernetes.io/part-of: runwhen-platform
runwhen.com/scc-exception: spilo
annotations:
runwhen.com/reason: >-
Spilo requires image UID 101; OpenShift restricted-v2 assigns a random
project UID and Spilo bootstrap chown/crontab fails. Scoped to the
Postgres ServiceAccount only — not a namespace-wide anyuid grant.
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:openshift:scc:anyuid
subjects:
- kind: ServiceAccount
name: rw-postgresql
namespace: runwhen-platform

Adjust metadata.namespace, the RoleBinding subject namespace, and the SA name ({release}-postgresql) to match your release.

Verify. After the binding exists, confirm the Postgres SA can actually use anyuid before the namespace owner runs Helm:

Terminal window
oc auth can-i use scc/anyuid \
--as=system:serviceaccount:${NS}:${RELEASE}-postgresql
# expect: yes

Prefer a custom SCC (Option C)? Define an SCC that lists only UID 101, still drops all capabilities, still forbids host access, and bind it the same way. This is stricter than anyuid because it hard-caps the allowed UID rather than accepting any. If your platform team already maintains custom SCCs for third-party workloads, this is likely how you will handle Postgres.

2. ClusterRoleBinding for Vault’s Kubernetes auth

What the ask is. Create one ClusterRoleBinding that lets Vault’s ServiceAccount call the Kubernetes TokenReview API. Vault uses that call to validate ServiceAccount tokens presented by other pods when they authenticate — nothing else.

Terminal window
kubectl create clusterrolebinding "${RELEASE}-vault-server-binding" \
--clusterrole=system:auth-delegator \
--serviceaccount="${NS}:${RELEASE}-vault"

Why it is cluster-scoped. TokenReview is a cluster resource — you can only grant access to it with a ClusterRoleBinding. That is why the Helm chart cannot ship this on behalf of a namespace-scoped admin: only cluster admins can create the binding. This is the same pattern used by every product that validates ServiceAccount tokens (external OIDC integrations, workload-identity plugins, admission webhooks).

What system:auth-delegator allows. Exactly two things:

  • create on tokenreviews.authentication.k8s.io
  • create on subjectaccessreviews.authorization.k8s.io

It grants no read or write access to workloads, Secrets, Namespaces, RBAC, or anything else in the cluster. It is Kubernetes’ least-privilege binding for “this service needs to answer ‘is this token valid?‘“.

3. Namespace pull secret

What the ask is. Create a kubernetes.io/dockerconfigjson Secret in the install namespace so the cluster can pull RunWhen’s images from the private Google Artifact Registry (or your enterprise mirror).

Why not rely on the cluster’s global pull secret. OpenShift nodes do not automatically inherit GAR credentials the way GKE does (via Workload Identity). Even when the cluster is inside the same GCP project that hosts the registry, node service accounts do not have roles/artifactregistry.reader on the RunWhen repository. Creating a namespace-scoped pull secret keeps the credential blast-radius small and lets you rotate it without touching cluster-wide config.

The namespace owner can create this secret themselves if they have secrets/create in the namespace; only involve the cluster admin if your policy centralizes registry credentials. The default secret name the chart looks for is gcr-pull-secret (change via images.pullSecrets in values).


The two Helm value overlays

Your onboarding pack ships two reference values files that pair with the SCC decisions above. The namespace owner layers them on top of their environment-specific overlay (domain, TLS, LLM, etc.):

Terminal window
helm upgrade --install rw ./runwhen-platform \
-n runwhen-platform --create-namespace \
-f values-example-openshift-restricted.yaml \
-f values-example-openshift-scc-exceptions.yaml \
-f your-domain-and-registry.yaml

The order matters: restricted first (sets the baseline of “run as whatever UID OpenShift gives you”), scc-exceptions second (overrides only the components that need a fixed UID).

Option A overlay — values-example-openshift-restricted.yaml

This file’s job is one thing: null every UID / group the chart pins by default, so every workload accepts the UID OpenShift assigns from the project range. Helm deep-merges values, which means omitting runAsUser does not remove it — you must explicitly set it to null for the chart to drop the key.

Show the full Option A overlay
# OpenShift / OKD — Option A: stay on restricted (no anyuid)
#
# Helm deep-merges values: set runAsUser/fsGroup to null to clear chart defaults.
# Do NOT set hostUsers — some OKD apiservers reject undeclared fields.
#
# Spilo is intentionally LEFT on its chart default UID 101 in this file so that
# admission FAILS loud if you have not applied Option B/C/D. To attempt a
# doomed arbitrary-UID Spilo experiment, null those keys yourself and expect
# bootstrapping chown/crontab failure.
global:
podSecurityContext:
runAsNonRoot: true
runAsUser: null
runAsGroup: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: null
capabilities:
drop: ["ALL"]
redis:
master:
podSecurityContext:
enabled: true
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
enabled: true
runAsNonRoot: true
runAsUser: null
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
neo4j:
securityContext:
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: null
capabilities:
drop: ["ALL"]
qdrant:
podSecurityContext:
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
runAsNonRoot: true
runAsUser: null
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
updateVolumeFsOwnership: false
vault:
server:
statefulSet:
securityContext:
pod:
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
container:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: null
capabilities:
add: [] # clear chart-default IPC_LOCK (forbidden on restricted)
drop: ["ALL"]
seaweedfs:
master:
podSecurityContext:
enabled: true
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
logs:
type: emptyDir
volume:
podSecurityContext:
enabled: true
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
logs:
type: emptyDir
filer:
podSecurityContext:
enabled: true
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
data:
type: persistentVolumeClaim
size: "5Gi"
storageClass: ""
logs:
type: emptyDir
s3:
podSecurityContext:
enabled: true
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault
llmGateway:
podSecurityContext:
runAsNonRoot: true
runAsUser: null
fsGroup: null
seccompProfile:
type: RuntimeDefault

A few points worth highlighting for reviewers:

  • runAsNonRoot: true is preserved everywhere. Nulling runAsUser allows OpenShift to pick one — it does not allow the pod to run as root.
  • readOnlyRootFilesystem: true and capabilities.drop: ["ALL"] stay in place across every component. Nothing here relaxes the container’s ability to write to its own filesystem or use privileged syscalls.
  • Vault has capabilities.add: [] — the chart normally adds IPC_LOCK so Vault can mlock() its memory to prevent unseal keys from swapping to disk. restricted does not allow IPC_LOCK, so on OpenShift Vault starts without mlock and prints a warning. This is a documented, accepted trade-off for OpenShift installs; production installs that require mlock can either use a custom SCC that permits IPC_LOCK for the Vault SA only, or switch to an external Vault.

Option B overlay — values-example-openshift-scc-exceptions.yaml

This file’s job is narrower: restore the fixed UID for Spilo so the image can actually start, and clear its seccomp profile so stock anyuid will match. Redis, Neo4j, and Vault exceptions are shipped commented out — enable them only if Option A hits an EACCES / capability failure in your specific cluster.

Show the full Option B overlay
# OpenShift / OKD — Option B: documented SCC exceptions for fixed-UID images
#
# Apply manifests/openshift/*.rolebinding.yaml as cluster-admin BEFORE or with
# this overlay. Do not grant namespace-wide anyuid.
#
# Layer ON TOP of values-example-openshift-restricted.yaml:
# helm upgrade ... \
# -f values-example-openshift-restricted.yaml \
# -f values-example-openshift-scc-exceptions.yaml
#
# Today the only REQUIRED exception for a working Postgres is Spilo.
# Redis / Neo4j / Vault rows are OPTIONAL — enable when Option A hits EACCES
# or an IPC_LOCK admission failure; keep commented until then.
# --- REQUIRED for bundled Spilo (does NOT work under restricted alone) -------
# Stock OpenShift `anyuid` forbids seccompProfiles — clear seccompProfile or
# anyuid will not match on admission.
postgresql:
spilo:
podSecurityContext:
runAsNonRoot: true
runAsUser: 101
fsGroup: 103
seccompProfile: null
containerSecurityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 101
capabilities:
drop: ["ALL"]
# Cluster-admin (once per namespace):
# oc apply -f charts/runwhen-platform/manifests/openshift/rw-postgresql-anyuid.rolebinding.yaml
#
# If pgdata PVC was created under a random OpenShift fsGroup, delete it before
# the first successful run as UID 101:
# kubectl -n "$NS" delete pvc pgdata-<release>-postgresql-0
# --- OPTIONAL: uncomment if Redis crashes with EACCES under Option A ---------
# redis:
# master:
# podSecurityContext:
# enabled: true
# runAsNonRoot: true
# runAsUser: 1001
# fsGroup: 1001
# seccompProfile:
# type: RuntimeDefault
# containerSecurityContext:
# enabled: true
# runAsNonRoot: true
# runAsUser: 1001
# allowPrivilegeEscalation: false
# readOnlyRootFilesystem: true
# capabilities:
# drop: ["ALL"]
# Then: oc adm policy add-scc-to-user anyuid -z <release>-redis-master -n "$NS"
# --- OPTIONAL: Neo4j UID 7474 ------------------------------------------------
# neo4j:
# securityContext:
# runAsNonRoot: true
# runAsUser: 7474
# fsGroup: 7474
# seccompProfile:
# type: RuntimeDefault
# --- OPTIONAL: Vault with mlock (IPC_LOCK) -----------------------------------
# Requires an SCC that allows IPC_LOCK (not stock restricted). anyuid is one
# blunt tool; prefer a custom SCC in production.
# vault:
# server:
# statefulSet:
# securityContext:
# pod:
# runAsNonRoot: true
# runAsUser: 100
# fsGroup: 1000
# seccompProfile:
# type: RuntimeDefault
# container:
# allowPrivilegeEscalation: false
# readOnlyRootFilesystem: true
# capabilities:
# add: ["IPC_LOCK"]
# drop: ["ALL"]

Reviewer-friendly notes:

  • Spilo still runs as an unprivileged UID. 101 is Zalando’s baked-in Postgres user, not root. Read-only root FS and dropped capabilities are still enforced.
  • The optional sections stay commented on purpose. Turning them on requires a matching cluster-admin binding; if a section is uncommented in a customer’s overlay, there should be a paired RoleBinding checked into the same change.

Component behaviour at a glance

ComponentOn stock restricted (Option A)If it doesn’t work
RunWhen first-party apps (PAPI, UI, AgentFarm, USearch, LLM gateway, …)Runs with any assigned UID
SeaweedFS, QdrantAdmits; validate in your clusterExternalize object store / vector DB
Postgres (Spilo)Does not workOption B (anyuid on the Postgres SA), Option C (custom SCC allowing UID 101), or Option D (external Postgres)
Vault (bundled)Admits without IPC_LOCK; mlock disabled with a warningCustom SCC allowing IPC_LOCK for Vault SA only, or external Vault
Redis (Bitnami)Usually admits; may hit EACCES on data files depending on image buildUncomment Redis section of Option B and add matching RoleBinding
Neo4jUsually admits; may hit EACCES on /dataUncomment Neo4j section of Option B and add matching RoleBinding

Install sequence

  1. Cluster admin — Create the pull secret (or delegate), apply the Postgres SCC RoleBinding, apply the Vault system:auth-delegator ClusterRoleBinding. Verify with oc auth can-i.
  2. Cluster admin (recommended) — Configure a ResourceQuota and LimitRange for the install namespace, or bake them into the ProjectRequestTemplate so every new project gets them automatically (see Resource quotas below).
  3. Namespace owner — Register Helm subchart repos, pull the OCI chart, prepare domain / registry / LLM overlays.
  4. Namespace ownerhelm upgrade --install with the restricted overlay + scc-exceptions overlay + your environment overlay.
  5. Both — Watch pod events. If a workload fails admission, the pod event will name the SCC it evaluated against — that is your diagnostic.
  6. Verify — Run the install-checklist.sh verify script from the onboarding pack.
  7. Runners — Deploy RunWhen Local pointed at the platform URL. Runner SCC needs are typically lighter than the platform stack.

Full self-hosted install steps that apply to every distribution (registry, DNS, TLS, LLM) live in Self-Hosted Deployment Requirements.

Resource quotas

The platform uses emptyDir scratch volumes for caches and working directories that can consume node disk space. The chart sets sizeLimit on every emptyDir, but this is an eviction signal, not a hard quota (see the main guide’s storage section for details).

Apply this to the install namespace before running Helm:

apiVersion: v1
kind: ResourceQuota
metadata:
name: runwhen-platform-quota
spec:
hard:
requests.ephemeral-storage: "50Gi"
limits.ephemeral-storage: "100Gi"
requests.storage: "200Gi"
persistentvolumeclaims: 20
---
apiVersion: v1
kind: LimitRange
metadata:
name: runwhen-platform-limits
spec:
limits:
- type: Container
default:
ephemeral-storage: "2Gi"
defaultRequest:
ephemeral-storage: "256Mi"
max:
ephemeral-storage: "10Gi"

Recommended for OpenShift: Bake these into the ProjectRequestTemplate so every new project is created with quotas from day zero:

apiVersion: template.openshift.io/v1
kind: Template
metadata:
name: project-request
objects:
- apiVersion: project.openshift.io/v1
kind: Project
metadata:
name: ${PROJECT_NAME}
- apiVersion: v1
kind: ResourceQuota
metadata:
name: platform-quota
namespace: ${PROJECT_NAME}
spec:
hard:
requests.ephemeral-storage: "50Gi"
limits.ephemeral-storage: "100Gi"
- apiVersion: v1
kind: LimitRange
metadata:
name: platform-limits
namespace: ${PROJECT_NAME}
spec:
limits:
- type: Container
default:
ephemeral-storage: "2Gi"
defaultRequest:
ephemeral-storage: "256Mi"
max:
ephemeral-storage: "10Gi"

Verify the template is active:

Terminal window
oc get project.config.openshift.io/cluster -o jsonpath='{.spec.projectRequestTemplate.name}'

If unset, apply the template and configure the cluster to use it:

Terminal window
oc apply -f project-request-template.yaml
oc patch project.config.openshift.io/cluster --type=merge \
-p '{"spec":{"projectRequestTemplate":{"name":"project-request"}}}'

Troubleshooting

unable to validate against any security context constraint

The pod’s requested UID / capabilities / seccomp profile does not match any SCC the pod’s ServiceAccount can use. The pod event will list which SCCs were evaluated and why each rejected the pod — read those messages first.

  • If it names restricted-v2 and complains about UID or fsGroup, the workload still has a pinned UID that the Option A overlay should have nulled — check for a values overlay that re-pins runAsUser.
  • If it names anyuid and complains about seccomp, the pod still has seccompProfile: RuntimeDefault. The Option B overlay clears this on Spilo; make sure your overlay merge order is -f restricted.yaml -f scc-exceptions.yaml (exceptions second).

Spilo CrashLoopBackOff with chown: Operation not permitted or crontab errors

The Postgres exception is not in effect for this pod. Either the RoleBinding is missing / points at the wrong SA, or the pod is not using {release}-postgresql. Confirm with:

Terminal window
oc get pod <spilo-pod> -o jsonpath='{.spec.serviceAccountName}{"\n"}'
oc auth can-i use scc/anyuid \
--as=system:serviceaccount:${NS}:$(oc get pod <spilo-pod> -o jsonpath='{.spec.serviceAccountName}')

If the PVC was created under a random OpenShift fsGroup before the exception was applied, delete it once so it can be recreated with fsGroup 103.

ImagePullBackOff despite correct values

The namespace pull secret is missing, misnamed, or the nodes cannot reach the registry. Confirm the secret exists in the install namespace, that images.pullSecrets in your values names it, and that pods can resolve and reach the registry host.

Vault log line: Failed to lock memory: cannot allocate memory

Expected on stock restricted — the chart cleared IPC_LOCK because SCC forbids it. Vault runs correctly but without mlock. If your policy requires mlock, use a custom SCC that permits IPC_LOCK for the Vault SA only, or run Vault externally.


TopicLink
Self-hosted prerequisites (all distributions)Self-Hosted Requirements
Pod security defaultsSelf-Hosted Requirements — Security
Enterprise registry (JFrog)JFrog Registry Setup
Enterprise registry (GAR)GAR Registry Setup
Private runnersSaaS with Private Runner

Get help

Email support@runwhen.com with your OpenShift/OKD version, your SCC posture (stock, custom SCC, or anyuid policy), and whether you plan to use bundled or external Postgres/Vault. Attaching oc describe pod output for any failing workload gets you a targeted answer faster than a general policy question.