Understanding OpenShift Security Context Constraints: The Complete Guide

|
Last Updated:
|
|
Understanding OpenShift Security Context Constraints
Credit: https://developer.ibm.com/developer/default/learningpaths/secure-context-constraints-openshift/intro/

In this guide, we will explain OpenShift Security Context Constraints (SCCs) in simple terms. SCCs are essential components of OpenShift that help keep cluster containers and applications secure. If you’ve worked with OpenShift, you might have heard of SCCs, whether during deployment troubleshooting or while configuring advanced security policies for your workloads. But what are OpenShift Security Context Constraints exactly, and why should you care about it? Let’s find out!

Understanding OpenShift Security Context Constraints (SCCs)

Introduction to Security Contexts and SCCs

Red Hat OpenShift provides robust security features to manage what containerized applications can and cannot do. Two critical components of this security framework are Security Contexts (SCs) and Security Context Constraints (SCCs).

Security Context Constraints (SCCs) are OpenShift-specific resources that extend Kubernetes’ native concept of security contexts. In Kubernetes, a security context defines privileges and access control settings for a pod or container. OpenShift SCCs enhances this by providing a cluster-wide mechanism to enforce the security settings consistently across all workloads.

Both security contexts and security context constraints work together to protect the nodes by restricting what pods and containers are allowed to do.

They enforce controls over several key security aspects, including:

  • Whether a pod can run as a privileged container
  • User ID (UID) or group ID (GID) the container runs as
  • Access to host resources, such as:
    • Host network
    • Host IPC and process namespaces
    • Host-mounted file systems
  • Linux capabilities the container can request or must drop (e.g., KILL, SYS_ADMIN, NET_ADMIN)
  • SELinux contexts applied to the container
  • Volume types the pod is permitted to use (e.g., hostPath, emptyDir, etc.)

Many cloud-native applications such as stateless microservices, APIs, and web apps etc… are designed to operate smoothly within these sandboxed, restricted environments and do not require elevated privileges or access to host-level resources.

However, some stateful workloads like databases, storage systems, monitoring agents, or networking plugins may require access to these protected host-level functions in order to operate correctly. These include the ability to:

  • Access raw storage devices
  • Mount host file systems
  • Use host network or process namespaces
  • Run as the root user or with specific Linux capabilities

In such cases, more permissive SCCs (e.g., privileged) must be used to grant the necessary access, while still maintaining control over security and risk.

Security Context Settings for Pods and Containers

There are different security context settings that can be applied to pods and containers to control specific Linux functions, organized into groups such as:

User and Group Identity settings

These settings control the user and group IDs under which processes and files operate. SCCs enforce these settings to restrict root access or define valid ID ranges.

  • Pod-level fields (spec.securityContext):
    • runAsUser: This is the field that is used to set the UID for all containers’ processes. This field uses the following strategy types to enforce access rules:
      • MustRunAs: Requires a specific runAsUser UID. Uses the configured UID as default and validates against it.
      • MustRunAsRange: Requires a UID range (uidRangeMin to uidRangeMax). Defaults to the minimum UID and validates against the range.
      • MustRunAsNonRoot: Ensures the pod runs as a non-root user (non-zero UID or USER directive in the image). No default UID provided.
      • RunAsAny: Allows any UID to be specified. No default provided.
    • runAsGroup: Defines the primary GID for containers’ processes (e.g., 2000). SCCs enforce valid GID ranges.
    • runAsNonRoot: Ensures containers run as non-root (boolean; true blocks UID 0). SCCs use MustRunAsNonRoot to mandate this.
    • fsGroup: This field Sets GID for volume ownership and permissions (e.g., 3000). It uses the following strategy types:
      • MustRunAs: Requires at least one range. Defaults to the first ID in the first range and validates against it.
      • RunAsAny: Allows any FSGroup ID. No default provided.
    • supplementalGroups: Adds extra GIDs for containers. It uses MustRunAs and RunAsAny strategy types .
    • supplementalGroupsPolicy: Defines how supplementary groups are calculated (Merge: includes /etc/group for primary user; nbvm : uses only fsGroup, supplementalGroups, runAsGroup; default is Merge if unset).
  • Container-level fields (spec.containers.securityContext):
    • runAsUser: Overrides pod-level UID for this container (e.g., 1001). SCCs validate against allowed UID ranges.
    • runAsGroup: Overrides pod-level GID for this container (e.g., 2001). SCCs ensure GID compliance.
    • runAsNonRoot: Enforces non-root for this container (boolean; true prevents root). SCCs align with MustRunAsNonRoot.

Privilege and Escalation Controls

These settings manage elevated permissions and prevent unauthorized privilege gains. SCCs restrict these settings to limit powerful containers.

  • Container-level fields only:
    • privileged: Runs container with full host access (boolean; true enables). SCCs often forbid this (e.g., restricted SCC disallows).
    • allowPrivilegeEscalation: Permits processes to gain more privileges (boolean; false blocks escalation). SCCs enforce AllowPrivilegedEscalation to restrict this.

Linux Capabilities Settings

These settings define kernel-level permissions for container processes. SCCs tightly control them to prevent abuse.

  • Container-level fields only:
    • capabilities:
      • add: Grants extra capabilities (e.g., [“NET_ADMIN”, “SYS_TIME”]); SCCs limit to allowedCapabilities.
      • drop: Removes capabilities (e.g., [“CHOWN”, “SETUID”]); SCCs mandate requiredDropCapabilities (e.g., ALL for restricted).

Here is a description of most common Linux capabilities.

Networking Capabilities:

  1. CAP_NET_BIND_SERVICE
    • Allows binding to TCP/UDP sockets below 1024 (privileged ports) without having to run as root user.
    • Example use case: Running an HTTP server on port 80.
  2. CAP_NET_ADMIN
    • Grants administrative control over the network stack (e.g., modifying routing tables, firewall rules, or interfaces).
    • Example use case: Configuring network settings inside the container.
  3. CAP_NET_RAW
    • Allows raw socket access (e.g., sending ICMP packets or custom network protocols, traffic monitoring/spoofing/scanning).
    • Example use case: Running diagnostic tools like ping, tcpdump.

Filesystem and Device Capabilities:

  1. CAP_CHOWN
    • Allows changing file ownership (chown).
    • Example use case: Modifying file permissions in shared volumes.
  2. CAP_DAC_OVERRIDE
    • Bypasses file read/write/execute permission checks.
    • Example use case: Accessing restricted files during debugging.
    • DAC is an abbreviation of Discretionary Access Control (Access to files is given to users at the discretion of owner)
  3. CAP_DAC_READ_SEARCH
    • Bypasses file/directory read/search permission checks.
    • Example use case: Reading restricted files without altering permissions.
  4. CAP_FOWNER
    • Acts as the owner of a file, even if the process isn’t the actual owner.
    • Example use case: Managing files in shared storage.
  5. CAP_MKNOD
    • Creates special files (e.g., block or character devices).
    • Example use case: Setting up device nodes in containers.

Process Management Capabilities:

  1. CAP_KILL
    • Allows sending signals (like SIGKILL) to arbitrary processes.
    • Example use case: Terminating misbehaving processes.
  2. CAP_SYS_BOOT
    • Reboots the system.
    • Rarely needed in containers; typically restricted.
  3. CAP_SYS_NICE
    • Modifies process priorities (e.g., nice, realtime).
    • Example use case: Prioritizing critical tasks in a container.
  4. CAP_SYS_PTRACE
    • Allows debugging or tracing processes (e.g., ptrace).
    • Example use case: Debugging applications inside the container.

System-Level Capabilities

  1. CAP_SYS_ADMIN
    • One of the most powerful capabilities, granting broad administrative rights (e.g., mounting filesystems, modifying namespaces).
    • Example use case: Mounting volumes inside the container.
    • Avoid it if you can!
  2. CAP_SYS_TIME
    • Changes the system clock.
    • Example use case: Synchronizing time in containers (rarely needed).
  3. CAP_SYSLOG
    • Reads/writes kernel logs (dmesg).
    • Example use case: Diagnosing low-level system issues.

Security and Auditing Capabilities:

  1. CAP_AUDIT_CONTROL
    • Enables/disables kernel auditing and modifies audit rules.
    • Example use case: Rarely needed in containers.
  2. CAP_AUDIT_WRITE
    • Writes records to the kernel audit log.
    • Example use case: Logging security events.
  3. CAP_SETFCAP
    • Sets file capabilities on files.
    • Example use case: Managing capabilities for executables.
  4. CAP_SETGID
    • Changes the group ID of the process.
    • Example use case: Switching between groups for access control.
  5. CAP_SETUID
    • Changes the user ID of the process.
    • Example use case: Switching between users for access control.

Read more on man capabilities.

CRI-O Default Capabilities in OpenShift:

By default, every container in a pod running on CRI-O gets the following Linux capabilities:

  • FOWNER
  • KILL
  • SETGID
  • FSETID
  • NET_BIND_SERVICE
  • CHOWN
  • SETPCAP
  • SETUID
  • DAC_OVERRIDE

These provide basic privileges for operations like file ownership, port binding, and process management.

OpenShift lets you control what capabilities containers can use by setting rules in Security Context Constraints (SCCs). You do this using the following three fields:

  • defaultAddCapabilities:
    • Capabilities automatically added to every container.
    • Containers do not need to request them.
  • allowedCapabilities
    • Capabilities that containers are allowed to request explicitly via their pod spec (securityContext.capabilities.add).
    • Not granted by default.
  • requiredDropCapabilities
    • Capabilities that are always removed from every container, even if requested or included by default.
    • Setting to ["ALL"] drops all capabilities and gives you a clean slate.

Filesystem Access Controls

Restrict access to container filesystems or volume mounts, enforced by SCCs to protect host resources.

  • Pod-level fields:
    • fsGroup: Applies GID to volumes for consistent ownership (e.g., 3000); SCCs validate via MustRunAs or RunAsAny strategy types.
  • Container-level fields:
    • readOnlyRootFilesystem: Mounts container’s root filesystem as read-only (boolean; true prevents writes); SCCs may require this for security.

SELinux Settings

Configure SELinux labels for process and file isolation, enforced by SCCs to ensure proper context.

The seLinuxContext field in an SCC specifies how SELinux contexts are enforced for pods and containers. It uses one of the following strategy types:

  • MustRunAs:
    • The MustRunAs strategy requires that all pods and containers run with a specific SELinux context defined in the SCC. This approach enforces a fixed and predefined SELinux label, providing strong workload isolation and stricter security boundaries.
    • The SELinux context label is configured through the seLinuxOptions field in the SCC, which can include:
      • User: Represents the SELinux user identity (e.g., system_u or user_u). It identifies the user context under which a process or object operates.
      • Role: Defines the role assigned to an SELinux user (e.g., object_r or sysadm_r). Roles restrict which types a user can access.
      • Type: Specifies the type of the object or process (e.g., httpd_t or etc_t). Type enforcement is the primary mechanism for access control in SELinux.
      • Level: Indicates the sensitivity level or range for Multi-Level Security (MLS) or Multi-Category Security (MCS), such as s0 or s0:c0.c1023. This is optional and used in systems with MLS/MCS policies.
    • Any pod or container using an SCC with the MustRunAs strategy must either:
      • Define SELinux labels matching those defined in the SCC in its securityContext, or
      • Rely on the default labels specified in the SCC.
    • If the pod defines SELinux labels that do not match those enforced by the SCC, the pod will be rejected and will not be allowed to run.

Example: SCC with MustRunAs strategy type and pre-allocated labels:

...
seLinuxContext:
  type: MustRunAs
  seLinuxOptions:
    type: container_t
    level: s0:c123,c456

Sample container spec;

...
spec:
  containers:
  - name: webapp
    image: nginx
    securityContext:
      seLinuxOptions:
        level: s0:c123,c456
        ...
  • RunAsAny:
    • The RunAsAny strategy allows pods to use any SELinux context. It does not enforce specific labels, making it ideal for trusted or dynamic workloads.
    • Pods can define any combination of SELinux fields (user, role, type, level)—or none at all.

If an SCC with seLinuxContext: MustRunAs lacks seLinuxOptions, OpenShift applies default SELinux labels to pods: user: system_u, role: system_r, type: container_t, and level: s0:cX,cY (namespace-specific MCS categories from openshift.io/sa.scc.mcs). Pods without securityContext.seLinuxOptions are accepted, as these defaults align with the SELinux targeted policy and MCS isolation, verifiable via oc get namespace <namespace> -o yaml or ps -eZ on a node.

      System Call and Kernel settings

      Limit system calls or kernel parameters, restricted by SCCs to prevent unsafe configurations.

      • Pod-level fields:
        • sysctls: Configures kernel parameters (e.g., name: net.core.somaxconn, value: “1024”). SCCs restrict to allowedSysctls.
      • Container-level fields:
        • seccompProfile: Applies seccomp filter for system calls (e.g., type: RuntimeDefault or Localhost, with localhostProfile). SCCs enforce allowedSeccompProfiles.

      Proc Filesystem settings

      Control /proc mount behavior in containers, limited by SCCs to reduce attack surface.

      • Container-level fields only:
        • procMount: Sets /proc mount type (e.g., Default masks sensitive entries, Unmasked exposes all); SCCs restrict allowedProcMountTypes.

      Default Security Context Constraints in OpenShift

      There are a number of default Security Context Constraints (SCCs) available in OpenShift, each designed to enforce specific security policies for pods and containers. These SCCs govern critical securityContext settings listed above, ensuring workloads run securely within defined boundaries. From highly restrictive options for general use to permissive configurations for administrative tasks, the default SCCs provide a flexible framework to balance security and functionality in an OpenShift cluster.

      Do not modify the default SCCs. Instead, you can create your custom ones.

      Listing Available SCCs in OpenShift

      You can list available SCCs in OpenShift using oc get command and specifying scc as the resource.

      oc get scc
      NAME                              PRIV    CAPS                   SELINUX     RUNASUSER          FSGROUP     SUPGROUP    PRIORITY     READONLYROOTFS   VOLUMES
      anyuid                            false                MustRunAs   RunAsAny           RunAsAny    RunAsAny    10           false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
      hostaccess                        false                MustRunAs   MustRunAsRange     MustRunAs   RunAsAny       false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","hostPath","persistentVolumeClaim","projected","secret"]
      hostmount-anyuid                  false                MustRunAs   RunAsAny           RunAsAny    RunAsAny       false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","hostPath","nfs","persistentVolumeClaim","projected","secret"]
      hostnetwork                       false                MustRunAs   MustRunAsRange     MustRunAs   MustRunAs      false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
      hostnetwork-v2                    false   ["NET_BIND_SERVICE"]   MustRunAs   MustRunAsRange     MustRunAs   MustRunAs      false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
      machine-api-termination-handler   false                MustRunAs   RunAsAny           MustRunAs   MustRunAs      false            ["downwardAPI","hostPath"]
      node-exporter                     true                 RunAsAny    RunAsAny           RunAsAny    RunAsAny       false            ["*"]
      nonroot                           false                MustRunAs   MustRunAsNonRoot   RunAsAny    RunAsAny       false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
      nonroot-v2                        false   ["NET_BIND_SERVICE"]   MustRunAs   MustRunAsNonRoot   RunAsAny    RunAsAny       false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
      privileged                        true    ["*"]                  RunAsAny    RunAsAny           RunAsAny    RunAsAny       false            ["*"]
      restricted                        false                MustRunAs   MustRunAsRange     MustRunAs   RunAsAny       false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
      restricted-v2                     false   ["NET_BIND_SERVICE"]   MustRunAs   MustRunAsRange     MustRunAs   RunAsAny       false            ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
      

      To print just the names of the SCCs;

      oc get scc -o name
      securitycontextconstraints.security.openshift.io/anyuid
      securitycontextconstraints.security.openshift.io/hostaccess
      securitycontextconstraints.security.openshift.io/hostmount-anyuid
      securitycontextconstraints.security.openshift.io/hostnetwork
      securitycontextconstraints.security.openshift.io/hostnetwork-v2
      securitycontextconstraints.security.openshift.io/machine-api-termination-handler
      securitycontextconstraints.security.openshift.io/node-exporter
      securitycontextconstraints.security.openshift.io/nonroot
      securitycontextconstraints.security.openshift.io/nonroot-v2
      securitycontextconstraints.security.openshift.io/privileged
      securitycontextconstraints.security.openshift.io/restricted
      securitycontextconstraints.security.openshift.io/restricted-v2
      

      The SCCs can be grouped as follows;

      Most Permissive (Least Restrictive)

      privileged

      • Most relaxed SCC – use only for cluster administration
      • Allows access to all privileged and host features
      • Allows running as any user, group, FSGroup, and SELinux context
      • Allows host mounts, privileged pods, host namespaces, and any capabilities

      hostaccess

      • Allows access to all host namespaces
      • Still requires pods to run with allocated UID and SELinux context
      • Warning: Grants host access to namespaces, file systems, and PIDs – use with caution

      hostmount-anyuid

      • Provides all features of restricted SCC
      • Allows host mounts and running as any UID and GID
      • Warning: Allows host file system access as any UID (including root) – grant with caution

      Moderately Permissive

      hostnetwork

      • Allows using host networking and host ports
      • Still requires allocated UID and SELinux context
      • Warning: A workload with hostnetwork on a control plane host is effectively root on the cluster

      node-exporter

      • Used for the Prometheus node exporter
      • Warning: Allows host file system access as any UID (including root)

      anyuid

      • Provides all features of the restricted SCC
      • Allows users to run with any UID and any GID

      Restrictive

      hostnetwork-v2

      • Similar to hostnetwork but with these differences:
        • ALL capabilities are dropped from containers
        • NET_BIND_SERVICE capability can be added explicitly
        • seccompProfile set to runtime/default by default
        • allowPrivilegeEscalation must be false or unset

      nonroot

      • Provides all features of restricted SCC
      • Allows users to run with any non-root UID
      • User must specify the UID or it must be in the container manifest

      nonroot-v2

      • Like nonroot but with these differences:
        • ALL capabilities are dropped
        • NET_BIND_SERVICE capability can be added explicitly
        • seccompProfile set to runtime/default by default
        • allowPrivilegeEscalation must be false or unset

      Most Restrictive

      restricted

      • Denies access to all host features
      • Requires pods to run with allocated UID and SELinux context
      • No longer available by default in OpenShift 4.11+ for new installations unless the access is explicitly granted.

      restricted-v2

      • Like restricted but with these differences:
        • ALL capabilities are dropped
        • NET_BIND_SERVICE capability can be added explicitly
        • seccompProfile set to runtime/default by default
        • allowPrivilegeEscalation must be false or unset
      • Default SCC for authenticated users in new OpenShift 4.11+ installations
      • Most restrictive of the default SCCs

      Get Detailed Summary of the SCC

      You can use oc get or oc describe commands to view more details of an SCC on Openshift.

      The oc describe command provides a more human-readable, detailed summary of a resource, focusing on runtime information. It’s especially useful for troubleshooting and understanding what’s happening with a resource at a glance.

      To get a runtime description of an SCC;

      oc describe scc anyuid
      Name:						anyuid
      Priority:					10
      Access:						
        Users:					<none>
        Groups:					system:cluster-admins
      Settings:					
        Allow Privileged:				false
        Allow Privilege Escalation:			true
        Default Add Capabilities:			<none>
        Required Drop Capabilities:			MKNOD
        Allowed Capabilities:				<none>
        Allowed Seccomp Profiles:			<none>
        Allowed Volume Types:				configMap,csi,downwardAPI,emptyDir,ephemeral,persistentVolumeClaim,projected,secret
        Allowed Flexvolumes:				<all>
        Allowed Unsafe Sysctls:			<none>
        Forbidden Sysctls:				<none>
        Allow Host Network:				false
        Allow Host Ports:				false
        Allow Host PID:				false
        Allow Host IPC:				false
        Read Only Root Filesystem:			false
        Run As User Strategy: RunAsAny		
          UID:					<none>
          UID Range Min:				<none>
          UID Range Max:				<none>
        SELinux Context Strategy: MustRunAs		
          User:					<none>
          Role:					<none>
          Type:					<none>
          Level:					<none>
        FSGroup Strategy: RunAsAny			
          Ranges:					<none>
        Supplemental Groups Strategy: RunAsAny	
          Ranges:					<none>
      

      The oc get command with -o yaml outputs the raw YAML definition of the resource as stored in the OpenShift API. This includes all metadata, spec, and configuration fields.

      Take for example, anyuid SCC.

      oc get scc anyuid -o yaml
      allowHostDirVolumePlugin: false
      allowHostIPC: false
      allowHostNetwork: false
      allowHostPID: false
      allowHostPorts: false
      allowPrivilegeEscalation: true
      allowPrivilegedContainer: false
      allowedCapabilities: null
      apiVersion: security.openshift.io/v1
      defaultAddCapabilities: null
      fsGroup:
        type: RunAsAny
      groups:
      - system:cluster-admins
      kind: SecurityContextConstraints
      metadata:
        annotations:
          include.release.openshift.io/ibm-cloud-managed: "true"
          include.release.openshift.io/self-managed-high-availability: "true"
          include.release.openshift.io/single-node-developer: "true"
          kubernetes.io/description: anyuid provides all features of the restricted SCC
            but allows users to run with any UID and any GID.
          release.openshift.io/create-only: "true"
        creationTimestamp: "2025-02-16T18:11:05Z"
        generation: 1
        name: anyuid
        resourceVersion: "341"
        uid: b4176dd2-52eb-4f3d-8c92-5d9276bd2c8a
      priority: 10
      readOnlyRootFilesystem: false
      requiredDropCapabilities:
      - MKNOD
      runAsUser:
        type: RunAsAny
      seLinuxContext:
        type: MustRunAs
      supplementalGroups:
        type: RunAsAny
      users: []
      volumes:
      - configMap
      - csi
      - downwardAPI
      - emptyDir
      - ephemeral
      - persistentVolumeClaim
      - projected
      - secret
      

      As already mentioned above, the purpose of the anyuid SCC is to extend the restricted SCC but allows containers to run as any UID/GID (including root). Here is a brief summary of the anyuid Security Constraint Context above:

      • Key Permissions:
        • runAsUser / fsGroup / supplementalGroups: RunAsAny (no UID/GID restrictions)
        • Volumes: Allows standard volume types (e.g., configMapsecret...) but blocks hostPath (allowHostDirVolumePlugin: false)
        • Capabilities:
          • Drops MKNOD (blocks creating device files)
          • No additional capabilities granted (allowedCapabilities: null, defaultAddCapabilities: null)
        • Privilege Escalation: Allowed (allowPrivilegeEscalation: true)
      • Security Restrictions:
        • Denies privileged containers (allowPrivilegedContainer: false)
        • Blocks host access:
          • No host networking (allowHostNetwork: false)
          • No host PID/IPC sharing (allowHostPID/IPC: false)
          • No host ports (allowHostPorts: false)
        • SELinux: Enforces MustRunAs (requires SELinux context)
      • Assigned To:
        • system:cluster-admins group (by default)
        • No regular users (users: [])
      • Priority10 (higher priority than default SCCs like restricted). See the SCC prioritization section below.
      • Use Case:
        • Legacy applications requiring root but no other host-level privileges.
        • Safer alternative to privileged SCC when only UID flexibility is needed.

      SCC Prioritization

      So, how does OpenShift determine which Security Context Constraint (SCC) to apply to a pod?

      OpenShift prioritizes Security Context Constraints (SCCs) to determine which SCC is applied to a pod during admission control. The prioritization process follows these steps:

      1. Highest Priority First: SCCs are sorted by their Priority field. A higher value takes precedence, and a nil (none) priority is treated as 0 (lowest). For example, an SCC with Priority: 10 is evaluated before one with Priority: 5.
      2. Most Restrictive to Least Restrictive: If multiple SCCs have the same priority, they are then sorted from most restrictive to least restrictive based on their constraints (e.g., an SCC requiring a specific RunAsUser is more restrictive than one allowing RunAsAny).
      3. Name-Based Sorting: If both priority and restrictiveness are equal, SCCs are sorted alphabetically by name.

      The admission controller retrieves all SCCs available to a pod based on the user, service account, and associated groups. It then evaluates them in the above order to find the first SCC that matches the pod’s requested security context (e.g., runAsUser, fsGroup, capabilities). If no SCC matches, the pod is rejected.

      For example, the default anyuid SCC, often granted to cluster administrators, has a higher priority (e.g., Priority: 10) to allow running pods as any user without specifying runAsUser. Custom SCCs should use the Priority field to ensure predictable ordering, and modifying default SCCs is discouraged to avoid issues during upgrades

      How Does OpenShift Use SCCs to Enforce Pod Security Policies?

      So, how does SCCs enforce Pod security policies exactly?

      • API Request: When a request to create a pod, via Deployment, ReplicaSet, or via oc create using a manifest file, is submitted to the API server, the system begins processing the request through a series of security and validation checks.
      • Authentication: The API server authenticates the requester using the configured authentication plugins such as OAuth, X.509 certificates, or service account tokens to verify their identity. If authentication fails, the request is immediately rejected.
      • RBAC Authorization: After successful authentication, the API server verifies if the authenticated entity has the necessary RBAC permissions to create pods in the specified namespace by checking against the defined Role and ClusterRole bindings. If the requester lacks appropriate permissions, the request is rejected with a permission error.
      • Schema Validation: Upon passing authorization, the API server validates the pod specification against the Kubernetes schema to ensure the manifest is well-formed and includes all the required fields according to the API version. Malformed requests are rejected at this stage.
      • Mutating Admission Controllers: Various mutating admission controllers process the request in sequence, potentially modifying the pod specification by adding default values, injecting sidecars, or setting resource limits. Some mutating controllers may reject the request if it violates certain policies.
      • SCC Admission Control: The SCC admission controller then processes the request with the following steps:
        • SCC Prioritization and Evaluation: The controller retrieves all available SCCs and sorts them in descending order of priority, with higher numerical values considered first.
        • Permission Check: The controller filters the SCCs to identify which ones are available to the pod’s service account, user, or groups based on the users and groups fields in each SCC.
        • Requirements Match: For each available SCC, the controller evaluates whether the security context requirements specified in the pod definition are permitted by the SCC constraints.
        • Priority-Based Selection: The controller selects the highest-priority SCC that satisfies all requirements, with priority determined by the numerical priority field in each SCC.
        • Pod Mutation: If the selected SCC requires modifications to the pod specification (such as adding SELinux contexts or dropping capabilities), the controller updates the pod definition accordingly.
        • SCC Annotation: The controller annotates the pod with openshift.io/scc: <scc-name> to indicate which SCC was applied, providing an audit trail for security compliance.
        • Rejection: If no valid SCC can be applied to the pod, the SCC admission controller rejects the request with a detailed error explaining which security constraints were violated.
      • Other Validating Admission Controllers: Additional validation checks are performed by other admission controllers, which may validate network policies, quota usage, or other cluster-specific requirements. Each controller may reject the request if its specific criteria are not met.
      • Final Validation and Persistence: After successfully passing through all admission controllers, the API server performs a final validation of the modified pod specification before persisting it to etcd and making it available for scheduling.

      Conclusion

      Security Context Constraints (SCCs) are a critical component of OpenShift’s security model, enabling administrators to enforce fine-grained access controls over containerized workloads. By defining what pods can and cannot do, SCCs help strike a balance between application functionality and cluster security.

      In our next guides, we will learn how to make SCCs available for use through service accounts as well as troubleshooting SCC-related errors.

      Other Tutorials

      Introduction to Role-Based Access Control (RBAC) in Kubernetes

      How to Use Secrets in Kubernetes Applications

      SUPPORT US VIA A VIRTUAL CUP OF COFFEE

      We're passionate about sharing our knowledge and experiences with you through our blog. If you appreciate our efforts, consider buying us a virtual coffee. Your support keeps us motivated and enables us to continually improve, ensuring that we can provide you with the best content possible. Thank you for being a coffee-fueled champion of our work!

      Photo of author
      Kifarunix
      Linux Certified Engineer, with a passion for open-source technology and a strong understanding of Linux systems. With experience in system administration, troubleshooting, and automation, I am skilled in maintaining and optimizing Linux infrastructure.

      Leave a Comment