Skip to content

How to work with non-root/Anyuid (SCC)

Component Version
OpenShift v4.21.22

Official documentation: Managing security context constraints

How SCC selection works

Based on: SCC Prioritization - OpenShift Documentation

When a workload is created, the service account is used to find SCCs. The admission controller:

  1. Retrieves all SCCs the service account can use (via RBAC).
  2. Generates default values for unset security context fields from the pod spec.
  3. Sorts candidates: highest priority first, then most restrictive first, then by name.
  4. Validates the pod against each SCC in order — the first match wins and is recorded in the openshift.io/scc annotation. If none match, the pod is rejected.

The result: pods get the most restrictive SCC that still allows them to run.

Tip

You can pin a specific SCC to a workload by setting the openshift.io/required-scc annotation on the pod template. The SCC must exist and the service account must have use permission for it.

Create project and service account

oc new-project anyuid-demo
oc create sa anyuid

Allow service account to use scc anyuid

oc adm policy add-scc-to-user -n anyuid-demo -z anyuid anyuid

It create a rolebinding:

% oc get rolebinding system:openshift:scc:anyuid -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: "2026-07-10T09:00:56Z"
  name: system:openshift:scc:anyuid
  namespace: anyuid-demo
  resourceVersion: "439866"
  uid: 7179d278-4b80-4f6c-b709-1e15ada8e08e
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:openshift:scc:anyuid
subjects:
- kind: ServiceAccount
  name: anyuid
  namespace: anyuid-demo

Deployment

without-anyuid

YAML, without-anyuid Deployment
kind: Deployment
apiVersion: apps/v1
metadata:
  name: without-anyuid
spec:
  replicas: 1
  selector:
    matchLabels:
      app: without-anyuid
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: without-anyuid
    spec:
      containers:
        - name: ubi
          image: registry.access.redhat.com/ubi9/ubi-micro:9.8-1782840931
          command:
            - /bin/sh
            - '-c'
            - |
              echo -n "id: "
              id;
              sleep infinity
Log output of the Pod
% oc logs deployment/without-anyuid
id: uid=1000750000(1000750000) gid=0(root) groups=0(root),1000750000

with-anyuid

YAML, with-anyuid Deployment
kind: Deployment
apiVersion: apps/v1
metadata:
  name: with-anyuid
spec:
  replicas: 1
  selector:
    matchLabels:
      app: with-anyuid
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: with-anyuid
    spec:
      serviceAccountName: anyuid
      containers:
        - name: ubi
          image: registry.access.redhat.com/ubi9/ubi-micro:9.8-1782840931
          command:
            - /bin/sh
            - '-c'
            - |
              echo -n "id: "
              id;
              sleep infinity
Log output of the Pod
% oc logs deployment/with-anyuid
id: uid=0(root) gid=0(root) groups=0(root)

List of pods

1
2
3
4
% oc get pods -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,SCC:.metadata.annotations."openshift\.io/scc",REQ-SCC:.metadata.annotations."openshift\.io/required-scc"
NAMESPACE     NAME                              SCC             REQ-SCC
anyuid-demo   with-anyuid-7769dfb79-6kpd5       anyuid          <none>
anyuid-demo   without-anyuid-55b5b5fd9f-8j9vb   restricted-v2   <none>

⚠️ Allow all service accounts to use an SCC with priority

Warning

This is a bad practice! Setting a high priority on a custom SCC and granting it cluster-wide causes all pods to pick it up — including platform components that may require a different SCC. This example demonstrates why priority must be used carefully.

Create a custom SCC based on nonroot-v2 but with priority: 100:

allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegeEscalation: false
allowPrivilegedContainer: false
allowedCapabilities:
- NET_BIND_SERVICE
apiVersion: security.openshift.io/v1
defaultAddCapabilities: null
fsGroup:
  type: RunAsAny
groups: []
kind: SecurityContextConstraints
metadata:
  name: nonroot-v2-with-prio
priority: 100
readOnlyRootFilesystem: false
requiredDropCapabilities:
- ALL
runAsUser:
  type: MustRunAsNonRoot
seLinuxContext:
  type: MustRunAs
seccompProfiles:
- runtime/default
supplementalGroups:
  type: RunAsAny
userNamespaceLevel: AllowHostLevel
users: []
volumes:
- configMap
- csi
- downwardAPI
- emptyDir
- ephemeral
- image
- persistentVolumeClaim
- projected
- secret

Grant access to all service accounts cluster-wide via a ClusterRoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system:openshift:scc:nonroot-v2-with-prio
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:openshift:scc:nonroot-v2-with-prio
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:serviceaccounts

After restarting pods, many now use the custom SCC — including platform components that shouldn't:

1
2
3
4
5
6
% oc get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,SCC:.metadata.annotations."openshift\.io/scc" | grep nonroot-v2-with-prio
anyuid-demo                 without-anyuid-55b5b5fd9f-l5jpq             nonroot-v2-with-prio
openshift-image-registry    image-pruner-29727360-6r9l5                 nonroot-v2-with-prio
openshift-machine-api       machine-api-controllers-789b98f676-49d9z    nonroot-v2-with-prio
openshift-operators         trident-operator-79ccfcdc4d-7l56t           nonroot-v2-with-prio
scc-test                    simple-http-server-555b496bd7-pskl5         nonroot-v2-with-prio

Because the priority is higher than any default SCC, the admission controller picks nonroot-v2-with-prio first. Components like machine-api-controllers and trident-operator now run under an SCC they were never designed for — potentially breaking them.


2026-07-10 2020-04-17 Contributors: Robert Bohne