πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Security intermediate ⏱ 25 minutes K8s 1.28+

OpenShift SCC: Security Context Constraints

Configure Security Context Constraints on OpenShift. Manage SCCs for pods requiring privileged access, host networking, custom UID/GID, and volume types.

By Luca Berton β€’ β€’ πŸ“– 7 min read

πŸ’‘ Quick Answer: Security Context Constraints (SCC) are OpenShift’s mechanism to control what pods can do β€” run as root, use host network, mount volumes, escalate privileges. Default SCCs range from restricted-v2 (most secure) to privileged (full access). Assign SCCs via oc adm policy add-scc-to-user <scc> -z <service-account>. Pods automatically use the most restrictive SCC that satisfies their requirements.

The Problem

On vanilla Kubernetes, Pod Security Admission (PSA) provides namespace-level enforcement with three profiles. OpenShift goes further with SCCs β€” fine-grained, per-pod security policies that control UID ranges, SELinux contexts, capabilities, volumes, and host access. When deploying workloads that need elevated privileges (databases, monitoring agents, GPU operators), you must grant the right SCC without over-permitting.

flowchart TB
    POD["Pod requests:<br/>runAsUser: 1000<br/>fsGroup: 1000"] --> ADMISSION["SCC Admission<br/>Controller"]
    ADMISSION --> CHECK{"Pod matches<br/>which SCC?"}
    CHECK -->|"Most restrictive match"| SCC_R["restricted-v2<br/>βœ… Allowed"]
    CHECK -->|"Needs more access"| SCC_A["anyuid<br/>(if granted)"]
    CHECK -->|"Needs host access"| SCC_P["privileged<br/>(if granted)"]
    CHECK -->|"No SCC matches"| DENIED["❌ Denied"]

Built-in SCCs (Least to Most Permissive)

SCCRun AsVolumesCapabilitiesHost NetworkUse Case
restricted-v2MustRunAsRange (random UID)configMap, secret, PVC, emptyDirDrop ALLNoDefault for all pods
nonroot-v2MustRunAsNonRootSame as restrictedDrop ALLNoApps that set their own non-root UID
hostmount-anyuidRunAsAnyhostPath + allDrop ALLNoMonitoring agents needing host mounts
anyuidRunAsAnySame as restrictedDrop ALLNoDatabases, legacy apps needing root
hostnetwork-v2MustRunAsRangeSame as restrictedDrop ALLYesIngress controllers, CNI plugins
node-exporterRunAsAnyhostPath + allDrop ALLYesPrometheus node exporter
hostaccessRunAsAnyhostPath + allDrop ALLYesHost-level monitoring
privilegedRunAsAnyALL (including hostPath)ALLYesGPU operators, CSI drivers, system daemons

The Solution

Check Current SCCs

# List all SCCs
oc get scc
# NAME                  PRIV   CAPS  SELINUX    RUNASUSER        FSGROUP    SUPGROUP   PRIORITY
# anyuid                false  []    MustRunAs  RunAsAny         RunAsAny   RunAsAny   10
# hostaccess            false  []    MustRunAs  RunAsAny         RunAsAny   RunAsAny   <none>
# hostmount-anyuid      false  []    MustRunAs  RunAsAny         RunAsAny   RunAsAny   <none>
# hostnetwork           false  []    MustRunAs  MustRunAsRange   MustRunAs  MustRunAs  <none>
# hostnetwork-v2        false  []    MustRunAs  MustRunAsRange   MustRunAs  MustRunAs  <none>
# nonroot               false  []    MustRunAs  MustRunAsNonRoot RunAsAny   RunAsAny   <none>
# nonroot-v2            false  []    MustRunAs  MustRunAsNonRoot RunAsAny   RunAsAny   <none>
# privileged            true   [*]   RunAsAny   RunAsAny         RunAsAny   RunAsAny   <none>
# restricted            false  []    MustRunAs  MustRunAsRange   MustRunAs  MustRunAs  <none>
# restricted-v2         false  []    MustRunAs  MustRunAsRange   MustRunAs  MustRunAs  <none>

# See which SCC a pod is using
oc get pod <pod-name> -o jsonpath='{.metadata.annotations.openshift\.io/scc}'
# restricted-v2

# Describe an SCC
oc describe scc anyuid

# Check who can use an SCC
oc adm policy who-can use scc anyuid

Grant SCC to ServiceAccount

# Grant anyuid to a service account (most common operation)
oc adm policy add-scc-to-user anyuid -z myapp-sa -n my-namespace

# Grant privileged (use sparingly!)
oc adm policy add-scc-to-user privileged -z gpu-operator-sa -n nvidia-gpu-operator

# Grant to a specific user
oc adm policy add-scc-to-user anyuid user1

# Grant to a group
oc adm policy add-scc-to-group anyuid system:serviceaccounts:my-namespace

# Remove SCC grant
oc adm policy remove-scc-from-user anyuid -z myapp-sa -n my-namespace

# Check which SCCs a service account can use
oc adm policy who-can use scc --list -z myapp-sa -n my-namespace

Using SCCs in Deployments

# Step 1: Create a ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mydb-sa
  namespace: my-database
---
# Step 2: Grant the SCC (via CLI or RoleBinding)
# oc adm policy add-scc-to-user anyuid -z mydb-sa -n my-database
#
# Or declaratively via ClusterRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: mydb-anyuid
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:openshift:scc:anyuid
subjects:
  - kind: ServiceAccount
    name: mydb-sa
    namespace: my-database
---
# Step 3: Reference SA in Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mydb
  namespace: my-database
spec:
  template:
    spec:
      serviceAccountName: mydb-sa     # Uses the SA with anyuid
      containers:
        - name: db
          image: registry.example.com/mydb:latest
          securityContext:
            runAsUser: 999             # anyuid allows specifying UID

Create Custom SCC

# Custom SCC β€” allows specific capabilities without full privileged
apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
  name: gpu-workload
allowPrivilegedContainer: false
allowHostNetwork: false
allowHostPorts: false
allowHostPID: false
allowHostIPC: true                     # Needed for NCCL shared memory
allowedCapabilities:
  - SYS_PTRACE                         # For debugging
  - IPC_LOCK                           # For RDMA memory pinning
  - SYS_RESOURCE                       # For ulimit settings
requiredDropCapabilities:
  - KILL
  - MKNOD
  - SYS_CHROOT
runAsUser:
  type: RunAsAny
seLinuxContext:
  type: MustRunAs
fsGroup:
  type: RunAsAny
supplementalGroups:
  type: RunAsAny
volumes:
  - configMap
  - downwardAPI
  - emptyDir
  - persistentVolumeClaim
  - projected
  - secret
  - hostPath                           # For GPU device access
allowHostDirVolumePlugin: true
readOnlyRootFilesystem: false
users: []
groups: []
priority: 10                           # Higher = preferred when multiple match
# Apply and grant
oc apply -f gpu-workload-scc.yaml
oc adm policy add-scc-to-user gpu-workload -z training-sa -n ai-workloads

SCC Priority and Selection Logic

# When a pod is admitted, OpenShift:
# 1. Finds all SCCs the pod's SA can use
# 2. Sorts by priority (highest first), then restrictiveness
# 3. Tries each SCC β€” first match wins
# 4. If none match β†’ pod rejected

# Check which SCC would be selected for a pod
oc adm policy scc-subject-review -z myapp-sa -n my-namespace -f pod.yaml

# Debug: why is my pod using the wrong SCC?
oc get pod <pod> -o jsonpath='{.metadata.annotations.openshift\.io/scc}'

Common SCC Assignments

# Databases (need specific UID)
oc adm policy add-scc-to-user anyuid -z postgresql-sa -n databases
oc adm policy add-scc-to-user anyuid -z mariadb-sa -n databases
oc adm policy add-scc-to-user anyuid -z mongodb-sa -n databases

# Monitoring (need host access)
oc adm policy add-scc-to-user privileged -z prometheus-node-exporter -n monitoring
oc adm policy add-scc-to-user hostnetwork-v2 -z ingress-nginx -n ingress

# GPU/AI workloads
oc adm policy add-scc-to-user privileged -z nvidia-gpu-operator -n nvidia-gpu-operator
oc adm policy add-scc-to-user privileged -z nvidia-driver-daemonset -n nvidia-gpu-operator

# Storage (CSI drivers)
oc adm policy add-scc-to-user privileged -z csi-driver-sa -n storage

Common Issues

IssueCauseFix
unable to validate against any SCCNo SCC matches pod requirementsGrant appropriate SCC to ServiceAccount
Pod running as wrong UIDrestricted-v2 assigns random UIDGrant anyuid SCC if specific UID needed
permission denied on volume mountSCC doesn’t allow volume typeGrant SCC with hostPath or appropriate volume
Container can’t bind port < 1024restricted-v2 drops NET_BIND_SERVICEGrant anyuid or add capability via custom SCC
GPU operator pods CrashLoopBackOffMissing privileged SCCGrant privileged to operator ServiceAccount
SELinux denialSCC SELinux context mismatchCheck seLinuxContext in SCC, use MustRunAs
Pod gets privileged unexpectedlySA has multiple SCC grantsCheck priority, remove unnecessary SCC grants

Best Practices

  • Use restricted-v2 by default β€” only escalate when needed
  • Grant to ServiceAccounts, not users β€” declarative and auditable
  • Create custom SCCs for specific needs β€” don’t grant privileged when anyuid + one capability suffices
  • Use priority field β€” ensures the right SCC is selected when multiple match
  • Audit SCC usage β€” oc get pods -A -o custom-columns='NAME:.metadata.name,SCC:.metadata.annotations.openshift\.io/scc'
  • Document why each SCC grant exists β€” add annotations to the RoleBinding
  • Never grant privileged to application workloads β€” only for infrastructure (operators, CSI, CNI)
  • Use oc adm policy scc-subject-review to test before deploying

Key Takeaways

  • SCCs are OpenShift’s fine-grained pod security mechanism (more powerful than PSA)
  • Default is restricted-v2 β€” random UID, no root, no host access, minimal capabilities
  • anyuid is the most commonly needed escalation β€” allows specific UID (databases, legacy apps)
  • privileged is for infrastructure only β€” GPU operators, CSI drivers, node-exporter
  • Grant via oc adm policy add-scc-to-user <scc> -z <sa> -n <ns>
  • Pods automatically get the most restrictive matching SCC
  • Create custom SCCs for specific capability needs instead of granting privileged
#scc #openshift #security-context #rbac #pod-security
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens