Control OpenShift Pod Permissions with SCCs and Service Accounts

|
Published:
|
|
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 system. 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

        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