Object storage on OpenShift Data Foundation (ODF) or Ceph RGW is documented
separately: OpenShift ODF and Ceph RGW Storage.
Follow that page only after this overlay is customized, or use the composed
k8s/overlays/openshift-odf-rgw profile instead of local /data PVC storage.Overview
This guide deploys CaseBender on OpenShift 4.x using the Kustomize overlay ink8s/overlays/openshift. The overlay is built from k8s/base and is
designed for the platform restricted-v2 SCC:
- arbitrary non-root UIDs (no fixed
runAsUser) - no privilege escalation; all capabilities dropped
RuntimeDefaultseccomp- read-only root filesystems
- no custom SCC (
anyuid, privileged, or host access)
k8s/base directly on OpenShift. Ingress is replaced by
Routes, placeholder Secrets are stripped from the render, and each
container gets an emptyDir at /tmp.
Prerequisites
- An OpenShift 4.x cluster with
NetworkPolicyenforcement (OpenShift SDN or OVN-Kubernetes). oc(andkubectlwith Kustomize, oroc kustomize).- Cluster-admin (or equivalent) to prepare the namespace, quotas, registry trust, and Routes.
- External PostgreSQL 14+ with TLS, and a Redis-compatible queue with TLS. This overlay does not operate the database or Redis lifecycle.
- DNS for the Route host and TLS terminated at the OpenShift router (edge).
- Signed, digest-pinned CaseBender images (and SBOMs) in a registry the cluster can pull. Production overlays must use digests, not floating tags.
- A secrets mechanism (External Secrets Operator, sealed secrets, or an approved injector). The rendered overlay contains no Secret objects.
What the overlay deploys
Platform objects: namespace
casebender, Routes, NetworkPolicies, ResourceQuota,
LimitRange, PodDisruptionBudgets, and (default profile) an RWX PVC casebender-data
mounted at /data on web.
See Integration Execution Plane
for connector-worker secrets and queue names.
Step 1: Install the OpenShift CLI
Step 2: Prepare the cluster
Namespace and SCC
The overlay creates namespacecasebender. Workloads must run as
restricted-v2 with an arbitrary UID:
anyuid or a custom SCC to make a fixed UID work. Images must
run as an arbitrary UID, keep writable paths group 0 / g=u, listen on an
unprivileged port, and write only to /tmp or /data.
Storage choice
Pick one:
The default overlay sets
STORAGE_PROVIDER=local and STORAGE_PATH=/data.
The PVC StorageClass must support ReadWriteMany if you run more than one
web replica. If it does not, use object storage and the ODF overlay.
CaseBender never creates buckets. ODF/RGW steps:
OpenShift ODF and Ceph RGW Storage.
ClamAV
Production user uploads stay quarantined until an external clamd scan. Compose bundles ClamAV; OpenShift does not. ProvideCLAMD_HOST / TLS or
CLAMD_SOCKET_PATH (sidecar). If the scanner is missing, attachments return
HTTP 409 until scan/promotion succeeds.
Network
Replace bootstrap0.0.0.0/0 CIDRs in k8s/overlays/openshift/network-policy.yaml
with approved ranges for PostgreSQL, Redis, registry, identity, storage, and
connectors before production. The ODF overlay additionally restricts RGW
egress; do not restore wildcard egress.
Step 3: Customize the overlay
Copyk8s/overlays/openshift (or openshift-odf-rgw) into an
environment-specific directory. Do not commit customer hostnames or
secrets into the product repository.
- Images — in
kustomization.yaml, replace everyregistry.example.com/casebender/...andreplace-with-releasewith the mirrored digest. - Route host — in
route.yaml, setspec.hoston all Routes to the approved DNS name (default placeholdercasebender.apps.example.com). Paths:/(web),/api/v1(API),/api/v1/ingestand/api/ingest(ingestion),/api/openapi.jsonand/docs(API docs). - PVC (local storage profile) — in
platform-controls.yaml, setstorageClassNameand size. - ConfigMap — non-secret settings (
casebender-config): public URL, storage provider, feature flags. TLS endpoints only in production. - NetworkPolicy — approved CIDRs only.
Step 4: Provision secrets
The overlay deletes the base placeholder Secret from the render. Createcasebender-secrets in namespace casebender before the first rollout.
k8s/overlays/openshift/external-resources.example.yaml is an External Secrets
example (excluded from Kustomize). Adapt it to your SecretStore. Typical keys:
POSTGRES_PRISMA_URLREDIS_URLAUDIT_INTEGRITY_SECRETFIELD_ENCRYPTION_KEYCREDENTIAL_ENCRYPTION_KEYWEBHOOK_KEY_PEPPERCONNECTOR_BUNDLE_SIGNING_KEYOAUTH_BROKER_SECRET
AUDIT_INTEGRITY_SECRET across upgrades. Rotating it invalidates the
audit chain. Never put secret values in ConfigMaps, Kustomize patches, or git.
Confirm the Secret exists and the render has no Secret objects:
Step 5: Render, validate, and apply
From the repository root (or your copied overlay tree):k8s/overlays/openshift-odf-rgw instead (it
composes the OpenShift overlay). Provision ObjectBucketClaims before
application startup. The adapter never creates buckets.
Web runs database migrations on startup. You do not run Prisma by hand.
Step 6: Verify
- every pod has a non-zero arbitrary UID and
restricted-v2 - writes to the root filesystem fail;
/tmp(and/dataif used) succeed - Routes serve HTTPS only; HTTP redirects
- default-deny NetworkPolicy blocks unapproved traffic
/api/health/liveand/api/health/readybehave as documented in Storage Health and Troubleshooting- a test upload is SHA-256 verified and, with clamd, leaves quarantine
validate.sh output, and SCC
review with the change record. Cluster execution is required before calling a
release “OpenShift validated.”
Disconnected registry
- On a connected host, download images, checksums, signatures, and SBOMs.
- Verify, then scan the mirrored digest under your policy.
oc image mirror(or the approved tool) by digest.- Configure
ImageDigestMirrorSet/ImageTagMirrorSetif required; wait for MachineConfigPool convergence. - Create a namespace pull secret and link it for pull. Do not commit it.
Proxy and custom CA
Cluster-wide proxy is a cluster-admin change (oc edit proxy/cluster). If
workloads need HTTPS_PROXY / HTTP_PROXY / NO_PROXY, include cluster
domains, service and pod CIDRs, PostgreSQL, Redis, and storage. Add an egress
rule for the proxy CIDR and port; the bootstrap policy does not open common
proxy ports.
For an internal CA, mount only the CA file (do not replace the image trust
store):
/etc/pki/ca-trust/source/anchors/casebender-ca.crt (subPath) and set
NODE_EXTRA_CA_CERTS to that path. Restart and test TLS to PostgreSQL, Redis,
storage, OIDC, and connectors. Never disable TLS verification as a CA
workaround.
Backup, upgrade, and rollback
Back up a consistency set: PostgreSQL, object storage (or/data snapshot),
secret versions (not plaintext in the archive), rendered manifest, and
Route/NetworkPolicy. See
Storage Backup and Restore.
Before upgrade, save live objects and the target render:
Troubleshooting
-
Pods crash with permission denied / SCC
Confirmrestricted-v2, no fixed UID, group-writable image paths, and/tmpemptyDir. -
Route 503 / no backends
Check probes, Service port (webappoften 80 → container), and rollout. -
Attachments HTTP 409 / “Image unavailable”
Worker malware scanner not reachable, or storage mutation not running. Restore clamd; objects stay quarantined until a clean verdict. -
Readiness 503 / storage
Local PVC vs ODF mismatch, missing buckets, or TLS/CA. Use Storage Health. -
Audit errors after upgrade
AUDIT_INTEGRITY_SECRETchanged. Restore the previous value.
Related documentation
- Overlay runbook in the repository:
k8s/overlays/openshift/README.md - OpenShift ODF and Ceph RGW Storage
- Storage Overview
- Upgrading
- Integration Execution Plane