Declarative Security Context Contraints Using RBAC

Posted: August 12th, 2020 | Author: | Filed under: Uncategorized | No Comments »

OpenShift contains a number of included security features and pods running within the cluster are governed by Security Context Constraints (SCC’s) which specify the actions that can be achieved as well as the resources that it can access. For new users beginning to work with OpenShift, their first experience with SCC’s is that their container will not run as the designed user ID and instead be assigned a random ID from a range. This is the anyuid SCC at work and it not only protects the container, but the underlying host.

There are circumstances where it may be necessary to modify the SCC the a pod is able to use (The restricted SCC is the default associated to pods). Traditionally, granting access to an SCC was accomplished by specifying the user (Service Account in most cases as it is used to run a pod) or group within the SCC.

For example, if a Service Account named my-special-pod was designated to run a particular workload in a namespace called example, the following command can be used to grant the pod access to the anyuid SCC and allow it to leverage the UID as specified in the container image:

$ oc adm policy add-scc-to-user anyuid -z my-special-pod

As a result, the following is added to the anyuid SCC:

users:
- system:serviceaccount:example:my-special-pod

While this method for modifying SCC’s has been around since the beginning of OpenShift 3, more recent versions of OpenShift 4 have recommended against directly modifying the included set of SCC’s as challenges have been seen during upgrades as the expected state of the SCC does not match the actual state.

Instead, an alternate approach for managing SCC’s through Role Based Access Control can accomplish the same goal without requiring direct intervention. By incorporating RBAC, policies can be created declaratively and integrate into an existing GitOps process.

Using RBAC to manage access to SCC’s is similar to managing any other aspects of OpenShift/Kubernetes, such as rights to another namespace. It requires the combination of a Role/ClusterRole and a binding to a particular resource. Since SCC’s are used by pods, and pods are run using Service Accounts, a Service Account is the resource that needs to be bound to the role.

Implementing RBAC

The first step is to create a new ClusterRole (since SCC’s are cluster scoped instead of namespace scoped) that will provide access to a given SCC. Roles/ClusterRoles make use of rules that allow access to resources and API verb operations. While the majority of roles that you will see leverage verbs, such as create, list, and delete, RBAC for SCC’s leverage the use verb for granting access. To provide access to the anyuid SCC requires the combination of the use verb, the anyuid resourceName, the security.openshift.io and the securitycontextconstraints resource. Fortunately the OpenShift CLI can be use to generate a ClusterRole with the combination of parameters previously:

$ oc create clusterrole allow-anyuid-scc --verb=use --resource=securitycontextconstraints.security.openshift.io --resource-name=anyuid

Take a look at the resource that was created:

$ oc get clusterrole allow-anyuid-scc -o yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: allow-anyuid-scc
rules:
- apiGroups:
    - security.openshift.io
  resourceNames:
    - anyuid
  resources:
    - securitycontextconstraints
  verbs:
    - use

With the ClusterRole now in place, it can then be bound to the Service Account that is used to run the pod. If you have not done so already, create a the project and Service Account:

$ oc new-project example
$ oc create sa my-special-pod

To bind the my-special-pod Service Account in the example namespace with the allow-anyuid-scc SCC, execute the following command:

$ oc create rolebinding anyuid-scc --clusterrole=allow-anyuid-scc --serviceaccount=my-special-pod

Take a look at the resource that was created:

$ oc get rolebinding anyuid-scc -o yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: anyuid-scc
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: allow-anyuid-scc
subjects:
- kind: ServiceAccount
  name: my-special-pod
  namespace: example

With the ClusterRole and RoleBinding now in place, newly created pods in the example namespace using he my-special-pod Service Account will run using the User ID as specified in the container. This can be confirmed by deploying a sample container within this namespace.

Create a sample application that starts up a basic RHEL8 based image using the my-special-pod service account which should enable the pod to run as the designated user ID.

$ oc run ubi8 --image=registry.redhat.io/ubi8/ubi --serviceaccount=my-special-pod --command -- /bin/bash -c 'while true; do sleep 3; done'

Since the pod was launched using the my-special-pod Service Account, confirm that is leveraging the anyuid SCC as enabled through the use of RBAC policies:

$ oc get pod -l=run=ubi8 -o jsonpath="{ .items[*].metadata.annotations['openshift\.io/scc'] }"

anyuid

The use of RBAC polices to manage access to Security Context Constraints avoids modifying the out-of-the-box policies that ship with OpenShift which could potentially compromise the stability of the platform, but more importantly aligns with the declarative nature of how OpenShift and Kubernetes is managed. Security has always been top of mind in OpenShift and it is great to see the management of the key features evolve with the platform.

Starting in OpenShift 4.5, RBAC ClusterRoles are now automatically created for the included set of SCC’s:

system:openshift:scc:anyuid
system:openshift:scc:hostaccess
system:openshift:scc:hostmount
system:openshift:scc:hostnetwork
system:openshift:scc:nonroot
system:openshift:scc:privileged
system:openshift:scc:restricted

The inclusion of these resources now eliminates the need to create ClusterRoles for each of the Security Context Constraints that you require access.