Skip to content

Gatekeeper — Automatic SCC Assignment

Warning

This is not recommended — you bypass one of OpenShift's core security features. Only use this in controlled environments where you fully understand the implications.

This setup uses OPA Gatekeeper mutations to automatically assign a specific SCC to every workload namespace cluster-wide. Gatekeeper labels each namespace and then injects the openshift.io/required-scc annotation onto pods, ensuring OpenShift uses the designated SCC instead of its default selection logic.

Official documentation:

Tested with:

Component Version
OpenShift v4.21.22
OPA Gatekeeper v3.21.0

How It Works

flowchart LR
    subgraph ns ["Namespace Mutation"]
        A([Namespace creation]) --> B{Name starts with\nopenshift-* or kube-*?}
        B -- Yes --> C([Skipped — no mutation])
        B -- No --> D{Has label\nscc-assignment?}
        D -- No --> E[Gatekeeper adds\nlabel=true]
        D -- Yes --> F([Label kept as-is])
    end

    subgraph pod ["Pod Mutation"]
        E --> G([Pod creation])
        F --> G
        G --> H{Has annotation\nopenshift.io/required-scc}
        H -- Yes --> X(Done)
        H -- No --> K{Label at Namespace\nscc-assignment==true?}
        K -- No --> I([Pod admitted — default SCC applies])
        K -- Yes --> J[Inject annotation\nopenshift.io/required-scc]
    end

Prerequisites

  • OpenShift 4.x cluster
  • OPA Gatekeeper installed with mutation enabled

Installation

1. Install the Gatekeeper Operator

Install the Gatekeeper Operator from OperatorHub (search for "Gatekeeper") and create a Gatekeeper CR with mutatingWebhook: Enabled. See the Chapter 5. Gatekeeper operator overview for details, or the upstream operator README.

2. Create the SCC and RBAC

In this example, all workloads should run with any UID. The built-in anyuid SCC has a higher priority and would always win, meaning it would also be applied to workloads not intended to run as anyuid.

That's the reason why I created a copy of anyuid without a prio:

apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
  name: anyuid-without-prio
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegeEscalation: true
allowPrivilegedContainer: false
allowedCapabilities: null
defaultAddCapabilities: null
fsGroup:
  type: RunAsAny
groups: []
priority: null
readOnlyRootFilesystem: false
requiredDropCapabilities:
  - MKNOD
runAsUser:
  type: RunAsAny
seLinuxContext:
  type: MustRunAs
supplementalGroups:
  type: RunAsAny
users: []
volumes:
  - configMap
  - downwardAPI
  - emptyDir
  - persistentVolumeClaim
  - projected
  - secret
oc apply -f https://examples.openshift.pub/cluster-configuration/gatekeeper-opa/automatic-scc-assignment/scc-anyuid-without-prio.yaml

Now it's time to allow all services accounts (group system:serviceaccounts) to use our own SCC.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: use-anyuid-without-prio
rules:
  - apiGroups:
      - security.openshift.io
    resourceNames:
      - anyuid-without-prio
    resources:
      - securitycontextconstraints
    verbs:
      - use
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: use-anyuid-without-prio
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: use-anyuid-without-prio
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: Group
    name: system:serviceaccounts
oc apply -f https://examples.openshift.pub/cluster-configuration/gatekeeper-opa/automatic-scc-assignment/clusterrole-use-anyuid-without-prio.yaml
oc apply -f https://examples.openshift.pub/cluster-configuration/gatekeeper-opa/automatic-scc-assignment/clusterrolebinding-use-anyuid-without-prio.yaml

3. Deploy the Gatekeeper mutations

Let's apply our two mutations.

3.1. Ensure the namespace labeling

apiVersion: mutations.gatekeeper.sh/v1
kind: AssignMetadata
metadata:
  name: assign-scc-assignment-label
spec:
  match:
    scope: Cluster
    kinds:
      - apiGroups:
          - ""
        kinds:
          - Namespace
    namespaceSelector: {}
    labelSelector:
      matchExpressions:
        - key: examples.openshift.pub/scc-assignment
          operator: DoesNotExist
    namespacesInScope:
      include:
        - "*"
      exclude:
        - kube-*
        - openshift-*
  location: 'metadata.labels."examples.openshift.pub/scc-assignment"'
  parameters:
    assign:
      value: "true"
oc apply -f https://examples.openshift.pub/cluster-configuration/gatekeeper-opa/automatic-scc-assignment/assign-namespace-label.yaml

3.2. Add openshift.io/required-scc to all Pods

Add the annotation openshift.io/required-scc to all pods in namespaces with a specific label.

Info

AssignMetadata only sets a value when the field is not already present — pods with an existing openshift.io/required-scc annotation are not touched.

apiVersion: mutations.gatekeeper.sh/v1
kind: AssignMetadata
metadata:
  name: assign-required-scc-annotation
spec:
  match:
    scope: Namespaced
    kinds:
      - apiGroups:
          - ""
        kinds:
          - Pod
    labelSelector: {}
    namespaceSelector:
      matchLabels:
        examples.openshift.pub/scc-assignment: "true"
  location: 'metadata.annotations."openshift.io/required-scc"'
  parameters:
    assign:
      value: anyuid-without-prio
oc apply -f https://examples.openshift.pub/cluster-configuration/gatekeeper-opa/automatic-scc-assignment/assign-metadata.yaml

4. Verify

Create a namespace and deploy an application:

1
2
3
oc create namespace test-app
oc project test-app
oc apply -k git@github.com:openshift-examples/kustomize/components/simple-http-server
1
2
3
% 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
test-app    simple-http-server-7fbb8879-sn9tx   anyuid-without-prio   anyuid-without-prio

🎉 SCC anyuid-without-prio is in use and required.

Opting Out

To exclude a namespace from automatic SCC assignment, explicitly set the label to "false":

oc label --overwrite namespace/test-app examples.openshift.pub/scc-assignment=false

Force to restart pods:

oc delete pods --all

Let's check the pods again:

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
test-app    simple-http-server-7fbb8879-7mvzb   restricted-v2   <none>

🎉 default SCC restricted-v2 is in use and no specific SCC is required.

The Gatekeeper mutation only fires when the label is absent, so an explicit "false" value is preserved and the SCC annotation is not injected.


2026-07-16 2026-07-15 Contributors: Robert Bohne