Running Pods With Particular UIDs – SCC Exploration With OpenShift

Containers have been subject to scrutiny, and skepticism on the merits of security. A whole post could be dedicated to these concerns. OpenShift provides an object called a Security Context Constraint (SCC), to allow for fine-grained control over what a pod is allowed to do. This includes what UID(s) a pod may run.

Lots of applications in the ecosystem require runtime with specific users. Sometimes this means a hard requirement on using a baked-in, expected username; or a requirement that the user have an /etc/passwd entry.

By default, OpenShift pods are brought up, and run as a random UID within a set range. This is a feature of a the default ‘restricted’ SCC in-place for the default service account. In OpenShift, pods are granted admission of privilege based on what service account a pod is started.

Let’s try to deploy a sample application that shows this in action.

new-app

Here we have a new OpenShift managed application – sourced from Git, using a simple Dockerfile strategy. Our runtime will be simple:

sample-dockerfile

We will add a a few image layers that simply add a new ‘myuser’ with UID 7000, add that as the active runtime user, and execute a simple entry point – print out the current id, and idle forever.

Some interesting things to note here:

Note my setting the user based on the UID, and not the username. For many SCC constraints, OpenShift will not allow setting a named user, such as ‘USER myuser.’ It does this to protect inadvertently running an image as a root user. By specifying a UID (non UID 0), we can put these concerns to rest. Try this with MustRunAsNonRoot – you will get a root verify error on deploy. If you can’t get around not running a process as root, check out the SCC approach for ‘anyuid’.

Also, note that I have my entry point idle forever. Why not just print the id, and exit 0? Well, if we do that, OpenShift will continually try to restart the pod until it reaches a back off state. We want to be able to easily see if our program runs as the UID 7000, we expect.

A first try:

randomuid

We see a large UID. Definitely not 7000. OpenShift is being sneaky, and substituting our ‘USER 7000’ line with a ‘USER <random in range>’ per our service account’s restricted SCC.

As a cluster admin user, let’s take a look at the SCC’s OOTB
currentsccs

We can see a few details about each SCC, and their parameters. Can they run pods as privileged? What SELinux Context(s) can they run as? What volume types can they mount? Running

oc describe scc <scc>

will show even more of the fine-grained control nature of a given SCC.

We want our image to run as UID 7000. To do this, we will copy the OOTB nonroot SCC; make it ours; create it within the system; create a new service account; add our new SCC to the service account; and redeploy our application as our new service account.

Lets create the SCC. We will start by copying the OOTB nonroot SCC. This will protect us from unexpected upgrade changes.
getnonrootscc

Open it up. We will need to change a few things, including the name (obviously), removing some UUID identifiers, and finally modify the priority. Service accounts can have access to multiple SCCs at a time based on group membership, or user admission. Only one is chosen though. With equal priority SCCs, OpenShift will chose the most restrictive. If we create our SCC with no priority and grant our service account access, our service account will bind back to restricted, since the restricted SCC is erm..more restrictive.

nonrootmodify

When done, create the new SCC with

oc create -f <filename>

Next, lets create a new service account using the following command

oc create sa mysa

Let’s grant the service account admission into our new SCC. Note that service accounts are qualified here using

system:serviceaccount:<namespace>:<name>

addscctoserviceaccount

We will need to update our deployment configuration to use our new service account. Since the DC is relative to it’s namespace, we don’t need to fully qualify it.

dcapplydcmodificationRedeploying the application, look what happens! Our UID is accepted!selecteduid

Also notice, our new service account being used. Our mysa, service account secret is being mounted. 
serviceaccountinaction

What if your set up is such that your deploy image doesn’t include a user as a layer? Such the case with an exclusive S2I build. You can always specify the UID directly within a deploy configs security context, like so. Note that SCCs still apply – of course 🙂
nodockerfile

There we have it! Specific UIDs running our application!