Control OpenShift Pod Permissions with SCCs and Service Accounts

|
Last Updated:
|
|
Control OpenShift Pod Permissions with SCCs and Service Accounts
Credit: https://developer.ibm.com/developer/default/learningpaths/secure-context-constraints-openshift/intro/

In this blog post, we will discuss how you can control OpenShift pod permissions with SCCs and service accounts. Have you ever deployed an app in OpenShift only to see pods crash due to permission errors? If that is not the case, then chances are you are running your applications with overly permissive settings? Remember, misconfigured pod permissions can expose your cluster to security risks, such as unauthorized access or privilege escalation. In OpenShift, Security Context Constraints (SCCs) and Service Accounts are essential tools for controlling what pods can and cannot do.

So, let’s see how you can create a deployment, assign pods to a service account, and bind the service account to a Security Context Constraint (SCC) to enforce security policies in OpenShift. Whether you’re deploying applications or securing multi-tenant clusters, mastering this process is key.

Control OpenShift Pod Permissions with SCCs and Service Accounts

Understanding Security Context Constraints

In our previous guide, we covered extensively about OpenShift SCCs. OpenShift SCCs are like the gatekeepers for pod permissions in OpenShift cluster. They define a set of conditions that a pod must run with in order to be accepted into the cluster. They dictate:

  • SELinux context requirements
  • Whether a pod can run privileged containers
  • Which host features (filesystems, networks, PIDs) a pod can access
  • Which user IDs a container can run with
  • What Linux capabilities are allowed

SCCs are enforced during the pod admission process. If a pod doesn’t meet the criteria defined by its assigned SCC, it won’t be allowed to run on the cluster.

So, why do SCCs matter? Consider this scenario:

  • An application requires write access to a host directory. Without proper constraints, this could potentially lead to serious security vulnerabilities if the application is ever compromised.
  • For example, assume you have a logging agent running as a DaemonSet that needs to read host logs for monitoring. It mounts the host log directory to access log files — and doesn’t necessarily need write access. However, if it’s accidentally given write permissions, things can quickly go wrong.
  • Even though the pod only needs to read logs, giving it write access without constraint is like letting a janitor into your server room with a sledgehammer — maybe they won’t use it, but do you really want to find out?
  • OpenShift’s Security Context Constraints (SCCs) help mitigate this risk by explicitly defining what resources and capabilities the pod can access, ensuring it only gets the permissions it truly needs.

What is Service Account and What Roles Do they Play?

Service account is OpenShift’s way of giving pods an identity. Pods use service accounts to interact with the API server, and these accounts are linked to SCCs to enforce the right permissions. If you don’t specify a service account, pods default to the default account in their namespace, which often uses restricted-v2 SCC.

Together, SCCs set the rules, and service accounts make sure pods follow them. For example, a pod needing to bind ports below 1024 requires a service account tied to an SCC that allows the NET_ADMIN capability. This combination prevents rogue pods from breaking your cluster.

In summary, the service accounts are essential for the following reasons:

  • They provide an identity for processes running in pods.
  • They can be granted specific permissions via RBAC.
  • They determine which SCCs a pod can use.

Create a Service Account

As already mentioned, a service account acts as the identity for pods running in OpenShift. By associating permissions (e.g., SCCs) with a service account, you can scope and manage access control effectively. This ensures that pods have only the necessary permissions and avoids over-privileged configurations.

Create the Service Account:

Use the oc create serviceaccount command to create a service account in your desired namespace.

   oc create serviceaccount <service-account-name>

Example:

   oc create serviceaccount scc-demo-sa

Note that service accounts are namespaced resources, meaning they exist within a specific namespace. If you don’t specify a namespace, the service account will be created in the current active namespace.

Specify a Different Namespace (Optional):

If you want to create the service account in a different namespace, use the -n option to specify the target namespace.

   oc create serviceaccount <service-account-name> -n <namespace>

Example:

   oc create serviceaccount scc-demo-sa -n scc-demo

Verify the Service Account:

Confirm that the service account was created successfully by listing all service accounts in the namespace.

   oc get sa

To list service accounts in a specific namespace:

   oc get sa -n <namespace>

Your newly created service account (scc-demo-sa) should appear in the list.

Inspect the Service Account (Optional):

For more details about the service account, use the oc describe command:

   oc describe sa <service-account-name>

Example:

   oc describe sa scc-demo-sa

Bind SCC to a Service Account

There are two primary ways to bind a SecurityContextConstraints (SCC) to a service account in OpenShift. These methods ensure that the service account has the necessary permissions and restrictions defined by the SCC when creating or running pods.

1. Using oc adm policy add-scc-to-user command

This method provides a quick and straightforward way to bind an SCC to a service account. It abstracts away the creation of the underlying RBAC resources, making it easy to use.

Two Syntax Options:

  1. Using the Full Service Account Name:
   oc adm policy add-scc-to-user <scc-name> system:serviceaccount:<namespace>:<service-account-name>

Example:

   oc adm policy add-scc-to-user restricted-v2 system:serviceaccount:scc-demo:scc-demo-sa
  1. Using the -z Flag:
    The -z flag is a shorthand for specifying the service account in the current namespace. It automatically resolves the service account name to the format system:serviceaccount:<current-namespace>:<service-account-name>.
   oc adm policy add-scc-to-user <scc-name> -z <service-account-name>

Example:

   oc adm policy add-scc-to-user restricted-v2 -z scc-demo-sa
  • The -z flag assumes the service account exists in the current active namespace. If you need to specify a different namespace, use the full service account name syntax.

In summary:

  • The add-scc-to-user command creates a ClusterRoleBinding under the hood.
  • This ClusterRoleBinding maps the SCC (as a ClusterRole) to the specified service account.
  • Since SCCs are cluster-scoped resources, OpenShift uses ClusterRoleBindings to ensure the binding applies across the entire cluster.

How to bind SCC to a service account using the oc adm policy add-scc-to-user command.

  • Determine the name of the service account and the namespace it belongs to. For example:
    • Service Account: scc-demo-sa
    • Namespace: scc-demo
  • Bind the SCC to the Service Account using either of the two syntax options above.
  • Verify the binding by checking the ClusterRoleBindings to confirm the SCC is bound:
   oc get clusterrolebinding
  • Look for a binding with a name like system:openshift:scc:<scc-name> (e.g., system:openshift:scc:restricted-v2).
  • To inspect the details:
   oc describe clusterrolebinding system:openshift:scc:restricted-v2

Additionally, you can bind an SCC to a user or a group;

oc adm policy add-scc-to-user <scc-name> <user-name>
oc adm policy add-scc-to-group <scc-name> <group-name>

Similarly, to remove a service account, user or a group from an SCC;

oc adm policy remove-scc-from-user <scc-name> -z <service-account-name>
oc adm policy remove-scc-from-user <scc-name> <user-name>
oc adm policy remove-scc-from-group <scc-name> <group-name>

2. Using RBAC (RoleBindings or ClusterRoleBindings)

This method involves explicitly creating roles or cluster roles and binding them to service accounts. It provides granular control over SCC bindings and is ideal for multi-team environments where fine-grained permissions are required.

1. Imperative Method

The imperative method uses oc commands to create roles, cluster roles, and bindings directly. This approach is quick and easy for ad-hoc configurations.

Create a Role or ClusterRole:

  • To create a namespace-scoped role:
oc create role <role-name> \
  --verb=use \
  --resource=securitycontextconstraints.security.openshift.io \
  --resource-name=<scc-name>
  • Example:
oc create role scc-demo-role \
  --verb=use \
  --resource=securitycontextconstraints.security.openshift.io \
  --resource-name=anyuid
  • To create a cluster-wide cluster role:
oc create clusterrole <cluster-role-name> \
  --verb=use \
  --resource=securitycontextconstraints.security.openshift.io \
  --resource-name=<scc-name>
  • Example:
oc create clusterrole scc-demo-clusterrole \
  --verb=use \
  --resource=securitycontextconstraints.security.openshift.io \
  --resource-name=anyuid

Bind the Role to a Service Account:

  • For a namespace-scoped role binding:
oc create rolebinding scc-demo-role-bind \
  --role=scc-demo-role \
  --serviceaccount=<namespace>:<service-account-name>
  • Example:
oc create rolebinding scc-demo-role-bind \
  --role=scc-demo-role \
  --serviceaccount=scc-demo:scc-demo-sa
  • For a cluster-wide cluster role binding:
oc create clusterrolebinding scc-demo-clusterrole-bind \
  --clusterrole=scc-demo-clusterrole \
  --serviceaccount=<namespace>:<service-account-name>
  • Example:
oc create clusterrolebinding scc-demo-clusterrole-bind \
  --clusterrole=scc-demo-clusterrole \
  --serviceaccount=scc-demo:scc-demo-sa

Verify the Binding:

  • For namespace-scoped bindings:
oc describe rolebinding scc-demo-role-bind -n <namespace>
  • For cluster-wide bindings:
oc describe clusterrolebinding scc-demo-clusterrole-bind

2. Declarative Method

The declarative method uses YAML files to define roles, cluster roles, and bindings. This approach is ideal for version-controlled configurations and GitOps workflows.

Define a Role or ClusterRole in YAML:

  • For a namespace-scoped role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: scc-demo-role
  namespace: <namespace>
rules:
- apiGroups: ["security.openshift.io"]
  resources: ["securitycontextconstraints"]
  resourceNames: ["<scc-name>"]
  verbs: ["use"]
  • For a cluster-wide cluster role:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: scc-demo-clusterrole
rules:
- apiGroups: ["security.openshift.io"]
  resources: ["securitycontextconstraints"]
  resourceNames: ["<scc-name>"]
  verbs: ["use"]

Define a RoleBinding or ClusterRoleBinding in YAML:

  • For a namespace-scoped role binding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: scc-demo-role-bind
  namespace: <namespace>
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: scc-demo-role
subjects:
- kind: ServiceAccount
  name: <service-account-name>
  namespace: <namespace>
  • For a cluster-wide cluster role binding:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: scc-demo-clusterrole-bind
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: scc-demo-clusterrole
subjects:
- kind: ServiceAccount
  name: <service-account-name>
  namespace: <namespace>

Apply the YAML files using oc apply:

   oc apply -f role.yaml
   oc apply -f rolebinding.yaml

Verify the Binding:

  • For namespace-scoped bindings:
oc describe rolebinding scc-demo-role-bind -n <namespace>
  • For cluster-wide bindings:
oc describe clusterrolebinding scc-demo-clusterrole-bind

3. Verify SCC Assignment to SA

You can finally verify that a Security Context Constraint (SCC) is correctly assigned to a Service Account,

oc adm policy who-can use scc SCC-NAME

E.g:

oc adm policy who-can use scc custom-scc

Your service account should be listed under users section.

Assigning a Service Account to a Deployment or Pod

To ensure that a pod runs with the permissions and identity of a specific service account, you can assign the service account. There are two primary ways to assign a service account to a Deployment or Pod:

  • Imperatively using the oc set serviceaccount command.
  • Declaratively by editing the YAML file and specifying the serviceAccountName field.

Imperative Method: Using oc set serviceaccount

The oc set serviceaccount command provides a quick and straightforward way to assign a service account to a Deployment, or other workload controllers.

  • The oc set serviceaccount command updates the spec.template.spec.serviceAccountName field in the Deployment (or other workload) YAML.
  • This triggers a rolling update of the pods, ensuring that new pods are created with the specified service account.

To assign a service account to a Deployment or a Pod via CLI:

  • Determine the name of the Deployment, DeploymentConfig, or other controller that manages the pod(s). For example:
    • Deployment: web-app
    • Namespace: scc-demo
  • Use the oc set serviceaccount command to assign the service account to the workload:
   oc set serviceaccount <workload-type> <workload-name> <service-account-name>

Example for a Deployment:

   oc set serviceaccount deployment web-app scc-demo-sa
  • Confirm that the service account has been updated:
   oc describe deployment web-app

Look for the Service Account field under the pod template specification. It should now show the assigned service account (scc-demo-sa).

Declarative Method: Editing the Resource YAML File

The declarative method involves explicitly defining the serviceAccountName field in the YAML file for the Deployment or Pod. This approach is ideal for version-controlled configurations and GitOps workflows.

The resource YAML’s file can be edited locally or by using the oc edit command to modify the resource directly in the cluster.

Thus:

  • if you have the resource YAML file locally, open it with your preferred editor and add the serviceAccountName field under the pod specification.
  • Example for a Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: scc-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      serviceAccountName: scc-demo-sa
      containers:
      - name: nginx
        image: nginx
  • Example for a Pod:
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  namespace: scc-demo
spec:
  serviceAccountName: scc-demo-sa
  containers:
  - name: nginx
    image: nginx

Apply the updated YAML file using oc apply:

   oc apply -f deployment.yaml

You also edit the resource directly using oc edit. For example:

oc edit deployment web-app-001 -n scc-demo

Locate the spec.template.spec section of the Deployment and add the serviceAccountName field:

Example snippet:

spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-app-001
  template:
    metadata:
      labels:
        app: web-app-001
    spec:
      serviceAccountName: scc-demo-sa
      containers:
      - name: nginx
        image: nginx

Save the changes and exit the editor. OpenShift will automatically apply the changes to the Deployment.

Confirm that the service account has been applied:

   oc describe deployment web-app

Or for a Pod:

   oc describe pod my-pod

Look for the Service Account field under the pod specification.

Key Notes:

  • If no serviceAccountName is specified, the pod defaults to the default service account in the namespace.
  • Service accounts are namespaced resources, so ensure the service account exists in the same namespace as the workload.

Step-by-Step Guide: Securing Your Deployment with SCCs

Let’s walk through creating a secure OpenShift deployment from scratch. By the end, you’ll have a pod running with tightly controlled permissions. We’ll assume you have access to OpenShift cluster CLI (oc).

Step 1: Create a Namespace/Project

First, let’s create a test namespace/project where we can play around with SCCs policies and service accounts.

We will use scc-demo as our new project. Feel free to use any name that suits you.

oc new-project scc-demo

When you create a new project with oc new-project command, it automatically switches your current context to that new project.

Step 2: Create a Service Account

Next, you need a service account to act as the pod’s identity. This keeps permissions scoped and manageable.

Refer to the steps above to create a service account.

Step 3: Use Existing SCCs to Control Pod Permissions

For most apps, the default restricted-v2 SCC is a safe be as it blocks privileged containers and enforces non-root users among other policies.

Therefore, you can list available SCCs:

oc get scc -o name

Sample output;

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

Describe an SCC to check its permission policies (Replace Name-Of-SCC with your respective SCC):

oc describe Name-Of-SCC

You can also show the info in YAML format.

oc get Name-Of-SCC -o yaml

Take for example, to view more details about anyuid SCC;

oc get scc anyuid -o yaml

To demonstrate how default SCCs can control Pod admissions, let’s deploy a basic Web App, for example Nginx or Apache.

We can simply create a deployment imperatively via CLI or declaratively via a Manifest YAML file. From the CLI, you can simply do;

oc create deployment web-app-001 --image=nginx:latest

When you create a deployment, like it is done above, the Deployment will likely fail. This happens because without specifying a service account with more permissive security settings, the deployment uses the default service account which is bound to the restricted-v2 SCC.

Looking at the restricted-v2 SCC configuration:

  • It enforces runAsUser: type: MustRunAsRange – containers must run as users within a specific range, not allowing specific user IDs that may be out of the allowed range. This range is typically defined by the project or namespace settings, with minimum and maximum values that restrict which user IDs can be used.
  • It requires dropping ALL capabilities except NET_BIND_SERVICE
  • It prevents privilege escalation with allowPrivilegeEscalation: false
  • It restricts volume types and host access

Public container images, for example, those from Docker Hub (like Nginx one used above) often fail because they:

  • Need to run as specific user IDs (often root)
  • Need to listen on privileged ports (80/443)
  • Require certain filesystem permissions

Since the restricted-v2 SCC forces containers to run with user IDs in a designated range rather than their expected IDs, these containers can’t access their configured files or bind to privileged ports, causing deployments to fail.

Let’s find out!

oc get deploy
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
web-app-001   0/1     1            0           6s

Sample output. No deployment is ready yet. Let’s check the pods.

oc get pods
NAME                           READY   STATUS             RESTARTS      AGE
web-app-001-76df47d8cc-mb5t5   0/1     CrashLoopBackOff   3 (25s ago)   77s

And there we go! The pod is stuck at CrashLoopBackOff. Let’s find out why;

Check the Pod’s logs;

oc logs pod/web-app-001-76df47d8cc-mb5t5
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?)
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/04/25 16:26:05 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2025/04/25 16:26:05 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)

As you can see from the logs, the pod is failing because it’s attempting to perform operations that require elevated privileges. Nginx runs as root user by default.

Since we didn’t explicitly specify a service account in the deployment, it defaulted to using the default service account in the namespace. In OpenShift, this service account is automatically associated with the restricted-v2 Security Context Constraint (SCC). You can confirm the same using the command below;

oc get pod/web-app-001-76df47d8cc-mb5t5 -o yaml | grep -E "openshift.io/scc|service"
    openshift.io/scc: restricted-v2
  namespace: scc-demo
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
  serviceAccount: default
  serviceAccountName: default
      - serviceAccountToken:
          - key: service-ca.crt
            path: service-ca.crt
          name: openshift-service-ca.crt

So, how can we make this Deployment run? Well, there are multiple ways in which you can resolve the issue encountered above.

  • Create your own custom image that sets Nginx to run as non-root user
  • Create a custom SCC that allows Deployment Pods to run as specific Nginx user e.g as UID 101
  • Use a less restricted SCC

Let’s see if we can use any default SCC that is less restrictive as per option 3 above to allow the Deployment containers to run. This can be done by analyzing a Deployment using OpenShift’s oc adm policy scc-subject-review command;

oc get deployment <deployment-name> -o yaml | oc adm policy scc-subject-review -f -

For example, to analyze the web-app-001 Deployment created above, you could run the command.

oc get deployment web-app-001 -o yaml | oc adm policy scc-subject-review -f -

Sample output;

RESOURCE                 ALLOWED BY   
Deployment/web-app-001   anyuid

This means that, among the available SCCs, anyuid could allow your Deployment pods to run. As such, we need to change the Deployment Pods/containers to run with anyuid SCC. Please avoid anyuid unless absolutely necessary.

To change Pod/Containers SCC, you need a service account that is bound to the Pod itself.

We have created a demo service account above, scc-demo-sa. You can create one if necessary.

Once you have the service account, you need to associate it with an SCC. In this example, we want to use anyuid SCC. Hence, to associate the service account, scc-demo-sa created above with anyuid SCC, you can use the command below:

oc adm policy add-scc-to-user SCC -z service-account

For example;

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

Next, configure the Deployment to use the service account that has been associated with an SCC that is likely to allow the Pods/containers to run.

You can do this either by (as already explained above):

  • Editing the Deployment and setting the service account name under spec.template.spec.serviceAccountName. E.g
oc edit deployment web-app-001
spec:
...
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web-app-001
    spec:
      serviceAccountName: scc-demo-sa
      containers:
      - image: nginx:latest
...

If specifying for a Pod, then set it under spec.serviceAccountName.

  • Using CLI command, oc set serviceaccount deployment <deployment> <service-account>. For example:
oc set sa deploy/web-app-001 scc-demo-sa

Immediately you set the service account, you should see the pods running.

oc get pods
NAME                           READY   STATUS        RESTARTS   AGE
web-app-001-75d5f596fc-gk54p   1/1     Running       0          3s
web-app-001-76df47d8cc-x4hrl   0/1     Terminating   0          3m22s

If you want to use custom SCC to permit Pod admission, check the next section.

Step 4: Create Custom SCC to Control Pod Admission

If none of the default SCCs provide enough security for your workloads or they might be too restrictive, you would create a custom SCC that meet your needs.

In the example above, we had to use anyuid SCC to permit the Deployment pod admission. This SCC is too permissive!!

As such, below is an example of how to create a custom SCC that allows running an application as a specific non-root user (e.g., 1001), without granting full anyuid privileges.

Create a YAML file for the custom SCC. Here is a sample custom SCC YAML.

cat custom-scc.yaml
apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
  name: custom-scc
allowPrivilegeEscalation: false
allowPrivilegedContainer: false
requiredDropCapabilities:
  - ALL
runAsUser:
  type: MustRunAs
  uid: 1001
seLinuxContext:
  type: MustRunAs
fsGroup:
  type: MustRunAs
  ranges:
    - min: 1000
      max: 2000
supplementalGroups:
  type: RunAsAny
volumes:
  - configMap
  - downwardAPI
  - emptyDir
  - persistentVolumeClaim
  - projected
  - secret

This custom SCC enforces strict security by requiring containers to run as UID 1001 (non-root), drops all Linux capabilities, blocks privilege escalation and privileged containers, restricts filesystem groups to UIDs 1000–2000, and only allows standard volume types (e.g., configMapsecret).

Apply the SCC to the cluster:

oc apply -f custom-scc.yaml

If you list the SCCs, you should see your custom one;

oc get scc -o name

Bind the custom SCC to the service account used by your Deployment. For example to bind the custom-scc SCC to the scc-demo-sa service account:

oc adm policy add-scc-to-user custom-scc -z scc-demo-sa

Confirm that the SCC is bound to the service account:

oc adm policy who-can use scc custom-scc

Step 5: Deploy an Application to use Custom SCC

Next, create a Deployment that will use the custom SCC created, verify that the application starts successfully. We will use Bitnami Nginx docker image to create a basic web app for testing. This image runs the Nginx process as the user 1001.

Sample Deployment manifest.

cat nginx-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  namespace: scc-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      serviceAccountName: scc-demo-sa 
      containers:
      - name: nginx
        image: bitnami/nginx:latest  
        ports:
        - containerPort: 80
        securityContext:
          runAsUser: 1001            
          allowPrivilegeEscalation: false

Key points from this manifest are:

  • The serviceAccountName field specifies the service account (scc-demo-sa) that has been bound to the custom SCC (custom-scc).
  • securityContext.runAsUser : The runAsUser field explicitly sets the UID to 1001, ensuring it matches the UID enforced by the custom SCC.
  • allowPrivilegeEscalation : This is set to false to prevent privilege escalation, aligning with the restrictions in the custom SCC.

Create the application by applying the manifest!

oc apply -f nginx-app.yaml

Check that the pod starts successfully:

oc get pods -l app=nginx-app

Example Output:

NAME                         READY   STATUS    RESTARTS   AGE
nginx-app-7c67cd5667-vngg4   1/1     Running   0          109s

Inspect the Pod Logs to verify that NGINX is running correctly:

oc logs nginx-app-7c67cd5667-vngg4 -n scc-demo
nginx 17:21:42.20 INFO  ==> 
nginx 17:21:42.20 INFO  ==> Welcome to the Bitnami nginx container
nginx 17:21:42.20 INFO  ==> Subscribe to project updates by watching https://github.com/bitnami/containers
nginx 17:21:42.21 INFO  ==> Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or application customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami/ for more information.
nginx 17:21:42.21 INFO  ==> 
nginx 17:21:42.21 INFO  ==> ** Starting NGINX setup **
nginx 17:21:42.23 INFO  ==> Validating settings in NGINX_* env vars
Certificate request self-signature ok
subject=CN = example.com
nginx 17:21:42.98 INFO  ==> No custom scripts in /docker-entrypoint-initdb.d
nginx 17:21:42.99 INFO  ==> Initializing NGINX
realpath: /bitnami/nginx/conf/vhosts: No such file or directory
nginx 17:21:43.00 INFO  ==> ** NGINX setup finished! **

nginx 17:21:43.02 INFO  ==> ** Starting NGINX **

Check Security Context to confirm that the pod is running with the correct UID (1001):

oc exec nginx-app-7c67cd5667-vngg4 -n scc-demo -- id

Example Output:

uid=1001(1001) gid=0(root) groups=0(root),1000

And there you go!

You have created a custom SCC, bound it to a service account and configured a deployment to use the security policies defined in an SCC via the service.

Conclusion

Security Context Constraints (SCCs) and Service Accounts are powerful tools for enforcing least-privilege security in OpenShift. By binding custom SCCs to dedicated Service Accounts and assigning them to workloads, you can control pod permissions without compromising cluster safety.

That marks the end of our guide on how to control OpenShift pod permissions with SCCs and service accounts.

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