Skip to content
Commitpedia
Log in Join & edit

Security Context Constraints (SCC) and why root containers fail on OpenShift

SCCs decide which user ID, capabilities and volumes a pod may use. Learn how restricted-v2 assigns random UIDs, how to see which SCC a pod got, and how to fix images instead of granting anyuid.

Not checked by a trusted editor yet Last edited Outdated?

Edit history of Security Context Constraints (SCC) and why root containers fail on OpenShift: 1 recorded edit
Edit history · 1 edit
Type
Article
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Reading
3 min

Security Context Constraints (SCCs) are OpenShift’s admission rules for pod security. When a pod is created, the API server checks its security settings against the SCCs that the pod’s service account and the requesting user may use. It either fills in safe defaults, or rejects the pod. An SCC controls, among other things, which user and group IDs a container runs as, whether it may be privileged, which Linux capabilities it gets, its SELinux context, seccomp profile and which volume types it may mount.

The default: restricted-v2

All authenticated users and service accounts can use the restricted-v2 SCC, and ordinary workloads end up there. Compared with the older restricted SCC it drops all capabilities (only NET_BIND_SERVICE can be added back), sets the seccomp profile to runtime/default and does not allow privilege escalation. The newest releases also add restricted-v3, which in addition runs pods in a Linux user namespace.

Its user ID strategy is MustRunAsRange. Every project gets a UID range in its openshift.io/sa.scc.uid-range annotation. If a pod does not request a user, it runs as the first UID in that range, a large number that differs between projects. The container’s user is always a member of the root group (GID 0), but it is not root.

oc get project shop-dev -o jsonpath='{.metadata.annotations.openshift\.io/sa\.scc\.uid-range}{"\n"}'

oc get pod web-6f7c9-abcde -o jsonpath='{.metadata.annotations.openshift\.io/scc}{"\n"}'

oc exec web-6f7c9-abcde -- id

Why images built for root break

Many images from public registries assume they run as root or as one specific user (for example UID 101), and their writable directories are owned by that user. Under a random UID the process cannot write its cache, PID file or log directory and exits with permission denied. Images that bind to ports below 1024 fail too. If a pod explicitly asks for a user outside the range, for example runAsUser: 0, admission refuses it with a message starting with pods "NAME" is forbidden: unable to validate against any security context constraint, followed by the reason from each SCC it tried.

The right fix: make the image UID-agnostic

The OpenShift image guidelines say how: files and directories the process writes to should belong to the root group and be group-writable, and executables need group execute permission. Because the random user is always in group 0, it can then write there.

FROM registry.access.redhat.com/ubi9/ubi-minimal
COPY app /opt/app
RUN mkdir -p /opt/app/data /opt/app/cache && \
    chgrp -R 0 /opt/app && \
    chmod -R g=u /opt/app
USER 1001
EXPOSE 8080
CMD ["/opt/app/bin/server", "--port", "8080"]
  • Listen on a port above 1024, such as 8080, and let the Service map port 80 if you need it.
  • Use a numeric USER. OpenShift overrides it with the project UID anyway, but numeric users also satisfy non-root checks.
  • Do not make /etc/passwd writable; the container runtime handles the random UID.
  • Write data that must survive to a mounted volume, not into the image.

When you really need a different SCC

Some software, such as monitoring agents or storage drivers, genuinely needs more rights. Do not edit the default SCCs; changes can break the platform and may be reset during upgrades. Instead, a cluster administrator grants a specific SCC to a dedicated service account, which only that workload uses.

oc create serviceaccount legacy-app -n shop-dev
oc adm policy add-scc-to-user anyuid -z legacy-app -n shop-dev
oc set serviceaccount deployment/legacy-app legacy-app -n shop-dev

Prefer the least powerful SCC that works: nonroot-v2 when the image runs as a fixed non-root UID, anyuid only when it truly needs root inside the container, and privileged only for trusted platform components. To make a workload fail loudly instead of silently landing on a different SCC, set the openshift.io/required-scc annotation in its pod template.

Inspecting SCCs

oc get scc
oc describe scc restricted-v2
oc adm policy scc-subject-review -f deployment.yaml
oc policy scc-review -z legacy-app -f deployment.yaml

scc-subject-review tells you which SCC would admit a manifest for you; scc-review checks it for given service accounts. Access can be granted directly in an SCC’s users and groups fields or through RBAC with the use verb on the securitycontextconstraints resource, so check both when you audit who may use an SCC.

Official documentation

Did this work for you?

No votes yet. Be the first.

If it did not work, the report form below tells the editors what went wrong.

See also

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Commitpedia +4,614 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?