What restricted-v2 enforces
Security Context Constraints (SCCs) are OpenShift's admission control for what a pod may ask
of the node. restricted-v2 is the default that authenticated users' pods get,
starting with OpenShift 4.11. Its older sibling restricted remains available in
some upgraded clusters.
Inspect it directly:
oc get scc restricted-v2 -o yaml
Here is what the fields mean in practice:
| Setting | Value in restricted-v2 | What it means for you |
|---|---|---|
runAsUser |
MustRunAsRange |
The UID comes from a range assigned to the namespace, not your image |
seLinuxContext |
MustRunAs |
Pods get MCS labels unique to the namespace |
fsGroup |
MustRunAs |
Group ownership of volumes comes from the namespace range |
supplementalGroups |
RunAsAny |
Supplemental groups are not constrained by this field |
allowPrivilegeEscalation |
false |
setuid binaries cannot gain privileges |
requiredDropCapabilities |
ALL |
All Linux capabilities are dropped |
allowedCapabilities |
NET_BIND_SERVICE |
The only capability a pod may add back |
seccompProfiles |
runtime/default |
The container runtime's default seccomp filter applies |
allowHostNetwork, allowHostPID, allowHostIPC, allowHostPorts |
false |
No access to host namespaces or ports |
allowHostDirVolumePlugin |
false |
No hostPath volumes |
allowPrivilegedContainer |
false |
No privileged containers |
volumes |
configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected, secret |
Everything else is rejected |
readOnlyRootFilesystem is not required by this SCC, though setting it to true
is still good hardening.
How your UID gets chosen
Each project has annotations with ID ranges:
oc get namespace payments -o yaml | grep 'openshift.io/sa.scc'
openshift.io/sa.scc.mcs: s0:c26,c15
openshift.io/sa.scc.supplemental-groups: 1000680000/10000
openshift.io/sa.scc.uid-range: 1000680000/10000
When a pod starts with no runAsUser, it gets the first UID of that range, here
1000680000. That number has three consequences:
-
It doesn't exist in
/etc/passwdin your image. - It doesn't own anything in your image.
- It differs between namespaces and clusters.
Its primary group, however, is root group (GID 0). Being in group 0 gives no special privileges, and it provides the standard route to making images work.
A compliant image
The technique that OpenShift's guidelines recommend is to give group 0 the same rights as the owner for anything the app writes to.
FROM registry.access.redhat.com/ubi9/ubi-minimal
COPY build/ /app/
RUN mkdir -p /app/cache /app/logs \
&& chgrp -R 0 /app \
&& chmod -R g=u /app
ENV HOME=/tmp
USER 1001
EXPOSE 8080
ENTRYPOINT ["/app/server", "--port=8080"]
Why each line is there:
-
chgrp -R 0andchmod -R g=ulet any UID in group 0 write where the owner can. Restrict this to directories the app really needs to write to. -
USER 1001declares a non-root numeric user, which keeps the image safe on plain Kubernetes. On OpenShift, it's overridden by a UID from the namespace range. -
HOME=/tmpavoids failures from tools that want to write to~, as there's no passwd entry for an arbitrary UID. -
Port 8080 avoids needing
NET_BIND_SERVICEfor a low port. Let the Service map 80 or 443 to it.
Don't set runAsUser in your Deployment to a fixed number. A value outside the
namespace's range fails admission.
A compliant pod spec
This spec passes both restricted-v2 and the restricted level of
Kubernetes Pod Security Standards:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-api
spec:
replicas: 3
selector:
matchLabels:
app: order-api
template:
metadata:
labels:
app: order-api
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.example.internal/payments/order-api:1.8.2
ports:
- containerPort: 8080
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Pods without these fields still get defaults from the SCC on OpenShift. Writing them out
means that the same manifest also works elsewhere, and that it passes Pod Security Admission
warnings. OpenShift's namespace label syncer manages pod-security.kubernetes.io
labels for most namespaces, and audit or warn messages may appear if your spec doesn't
declare these settings.
Reading the errors
| Error | Cause | Fix |
|---|---|---|
unable to validate against any security context constraint with a field path |
Pod asks for something the SCC forbids | The message says which field; remove or change that field |
Invalid value: 0: must be in the ranges |
Fixed runAsUser outside the namespace range |
Remove runAsUser |
mkdir: Permission denied in logs |
App writes where group 0 has no permission | chmod g=u in the image, or mount an emptyDir there |
bind: permission denied on port 80 |
Low port without the capability | Listen on 8080 and map at the Service |
CrashLoopBackOff with id: cannot find name for user ID |
Script expects a passwd entry | Fix the script, or write the entry in the entrypoint when the file is writable |
| Files unreadable on a PVC | Volume ownership or SELinux label mismatch | Check fsGroup handling and how the storage driver applies it |
Pod has openshift.io/scc: anyuid unexpectedly |
Service account or a group has that SCC | Check bindings; see next section |
Finding out which SCC applied
The admission plugin records the outcome on the pod:
oc get pod <pod> -n payments -o jsonpath='{.metadata.annotations.openshift\.io/scc}{"\n"}'
To audit a whole namespace, or a tool you've just installed:
oc get pods -n monitoring-tool -o custom-columns='NAME:.metadata.name,SCC:.metadata.annotations.openshift\.io/scc'
If a pod runs under something other than what you expected, it's usually because the service
account was granted access to a more permissive SCC. When several SCCs are available,
OpenShift orders them by priority, then from most to least restrictive, and it picks the
first that validates. Having anyuid available changes which one a pod gets,
because that SCC has a higher priority.
To test a manifest without deploying it, the following asks what the SCC admission would decide:
oc adm policy scc-subject-review -f deployment.yaml
To see who has access to a given SCC:
oc adm policy who-can use scc anyuid
When something really needs more
A few workloads have real reasons to ask for more: CNI plugins, storage drivers and
node-level agents that read host files. Don't reach straight for privileged.
Take these steps instead:
-
Ask if it's actually needed. Can logs arrive over OTLP rather than
through a
hostPath? Can a metric come from the API instead of the node? -
Prefer a custom SCC with only what's needed. Some teams copy
restricted-v2, then add one volume type or one capability. Don't edit the built-in SCCs, as updates may reset them, and other things depend on them. -
Bind it to a dedicated service account in a dedicated namespace, with a
Rolegrantinguseon that one SCC. - Document the reason and the owner, and include it in your review cycle.
Be careful with anyuid as a quick fix for a permission error. It often "works,"
by letting an image run as root, hiding the problem and removing a real safeguard.
Questions to ask of any third-party tool
Monitoring agents are among the most frequent reasons that clusters collect SCC exceptions, as the OpenShift monitoring guide notes. Ask each vendor:
- Which SCC does each pod need, in each deployment mode?
- Which privileges map to which features? What do I lose if I refuse a given privilege?
- Does any component run as root?
-
Does it need
hostPath,hostNetworkorhostPID, and why? - What is its webhook's failure policy? See the admission webhooks guide.
Then verify using the audit command above, rather than relying on the data sheet.
How Wrentrix runs
Wrentrix runs under the default restricted-v2 SCC: least-privilege pods, no
root and no extra SCCs to grant. You can check this yourself with the same
openshift.io/scc audit shown above. Its webhook is fail-open, so pods still
start if the agent is unavailable. The security
and access control page covers access and audit.
Frequently asked questions
What is the difference between restricted and restricted-v2 in OpenShift?
restricted-v2 is the stricter default that came with OpenShift 4.11. It drops
all capabilities, disallows privilege escalation and requires the runtime default seccomp
profile, which lines it up with the Kubernetes restricted Pod Security Standard. New
clusters use it by default for authenticated users, while upgraded clusters may have the
older one available.
Why does my container get a random UID on OpenShift?
Under MustRunAsRange, the UID comes from a range assigned to the project, so
that different namespaces get separate identities. It's not actually random; it's the start
of the namespace's range, recorded in its annotations. Design images to work with any
non-root UID in group 0.
How do I fix permission denied errors on OpenShift?
Find the path from the log, then make it writable for group 0 in the image with chgrp
-R 0 and chmod -R g=u, or mount an emptyDir there. Check
that the app doesn't assume a home directory or a fixed username. Avoid granting
anyuid as the fix, since it removes a safeguard.
How do I check which SCC a pod is using?
Read the openshift.io/scc annotation on the running pod, using oc get
pod with a JSONPath or oc describe pod. If it isn't what you expected,
check which SCCs the service account can use. Priority and restrictiveness decide which one
is chosen.
Can I run containers as root on OpenShift?
It's possible by granting an SCC like anyuid to the service account, but it
isn't the default, and it should need a good reason. Most images that need root only need a
change to file permissions and listening ports. Do the review before granting, and limit it
to a dedicated service account.