{{announcement.body}}
{{announcement.title}}

Deploy Application on Open-Shift that Requires Elevated Privileges on Specific Paths

DZone 's Guide to

Deploy Application on Open-Shift that Requires Elevated Privileges on Specific Paths

In this article, see how to deploy an application on Open0Shift that requires elevated privileges on specific paths.

· Cloud Zone ·
Free Resource

For this document, we have created an Angular UI application and containerized it using NGINX for OpenShift 4.3.

Deploying Application by Updating Dockerfile

By default, OpenShift Container Platform runs containers using an arbitrarily assigned user ID. This provides additional security against processes escaping the container due to a container engine vulnerability and thereby achieving escalated permissions on the host node.

For an image to support running as an arbitrary user, directories and files that may be written to by processes in the image should be owned by the root group and be read/writable by that group. Files to be executed should also have group execute permissions.

Adding the following to your Dockerfile sets the directory and file permissions to allow users in the root group to access them in the built image:

Textile
 




x


 
1
RUN chgrp -R 0 /some/directory && \
2
    chmod -R g=u /some/directory



Note: /some/directory is the path on which image needs privileged access.

Because the container user is always a member of the root group, the container user can read and write these files. The root group does not have any special permissions (unlike the root user) so there are no security concerns with this arrangement. In addition, the processes running in the container must not listen on privileged ports (ports below 1024), since they are not running as a privileged user

Sample Dockerfile of our NGINX + Angular Application

Dockerfile
 




x


 
1
FROM nginx:1.13.3-alpine
2
 
          
3
RUN rm -rf /etc/nginx/nginx.conf.default && rm -rf /etc/nginx/conf.d/default.conf
4
 
          
5
COPY /nginx/nginx.conf /etc/nginx/nginx.conf
6
COPY /nginx/nginx.conf /etc/nginx/conf.d/nginx.conf
7
 
          
8
## Remove default nginx index page
9
RUN rm -rf /usr/share/nginx/html/*
10
 
          
11
# Copy code from dist folder to nginx folder
12
COPY  /dist/my-angular-app/ /usr/share/nginx/html
13
 
          
14
RUN chgrp -R 0 /var/cache/ /var/log/ /var/run/ && \
15
    chmod -R g=u /var/cache/ /var/log/ /var/run/
16
 
          
17
EXPOSE 9090
18
#Entry point of application
19
ENTRYPOINT ["nginx", "-g", "daemon off;"]



In case the team wants specific user id during execution, the following steps can be followed:

Because the user ID of the container is generated dynamically, it will not have an associated entry in /etc/passwd. This can cause problems for applications that expect to be able to look up their user ID. One way to address this problem is to dynamically create a passwd file entry with the container’s user ID as part of the image’s start script. This is what a Dockerfile might include:

Dockerfile
 




xxxxxxxxxx
1


 
1
RUN chmod g=u /etc/passwd
2
ENTRYPOINT [ "uid_entrypoint" ]
3
USER 1001



Where uid_entrypoint contains: 

Dockerfile
 




xxxxxxxxxx
1


 
1
if ! whoami &> /dev/null; then
2
  if [ -w /etc/passwd ]; then
3
    echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:${HOME}:/sbin/nologin" >> /etc/passwd
4
  fi
5
fi



Study more about using User Ids

Deploying Same Application by Using Service Accounts

Service Accounts Overview

A service account is an OpenShift Container Platform account that allows a component to directly access the API. Service accounts are API objects that exist within each project. Service accounts provide a flexible way to control API access without sharing a regular user’s credentials.

When you use the OpenShift Container Platform CLI or web console, your API token authenticates you to the API. You can associate a component with a service account so that they can access the API without using a regular user’s credentials. For example, service accounts can allow:

  • Replication controllers to make API calls to create or delete pods.

  • Applications inside containers to make API calls for discovery purposes.

  • External applications to make API calls for monitoring or integration purposes.

Each service account’s user name is derived from its project and name:

Shell
 




xxxxxxxxxx
1


 
1
system:serviceaccount:<project>:<name>



Every service account is also a member of two groups:

  • system:serviceaccounts Includes all service accounts in the system.

  • system:serviceaccounts: Includes all service accounts in the specified project.

Each service account automatically contains two secrets:

  • An API token

  • Credentials for the OpenShift Container Registry

The generated API token and registry credentials do not expire, but you can revoke them by deleting the secret. When you delete the secret, a new one is automatically generated to take its place.

Default Project Level Service Accounts and Roles

Three service accounts are automatically created in each project:

Service Account Usage
builder Used by build pods. It is given the system:image-builder role, which allows pushing images to any imagestream in the project using the internal Docker registry.
deployer Used by deployment pods and given the system:deployer role, which allows viewing and modifying replication controllers and pods in the project.
default Used to run all other pods unless they specify a different service account.

All service accounts in a project are given the system:image-puller role, which allows pulling images from any imagestream in the project using the internal container image registry.

Note : Our strategy is to use default service account for pulling image via import-image(image stream) and creating deployment config. But for deploying our application we will our custom service account as we will give it sufficient access.

Before creating service account, we need to login to correct project inside our cluster :

Shell
 




x


 
1
[root@hou0posa01 ~]# oc project
2
Using project "test" on server "https://<hostname>:<port>".



Creating Service Account

1. To create a new service account in the current project:

Java
 




xxxxxxxxxx
1


 
1
$ oc create sa <service_account_name> serviceaccount "robot" created
2
Exmaple: `oc create sa robot`



2. Optional: View the secrets for the service account

Shell
 




x


 
1
[root@hou0posa01 ~]# oc describe sa robot
2
Name:                robot
3
Namespace:           test
4
Labels:              <none>
5
Annotations:         <none>
6
Image pull secrets:  robot-dockercfg-q2x7n
7
Mountable secrets:   robot-dockercfg-q2x7n
8
                     robot-token-6n8pw
9
Tokens:              robot-token-6n8pw
10
                     robot-token-rdkpn
11
Events:              <none>



3. Before we give privileges to our service account, we need to understand SCC 

** Security Context Constraints (SCC)** It is basically used for pod restriction, which means it defines the limitations for a pod, as in what actions it can perform and what all things it can access in the cluster.

OpenShift provides a set of predefined SCC that can be used, modified, and extended by the administrator.

Shell
 




xxxxxxxxxx
1
10


 
1
[root@hou0posa01 ~]# oc get scc
2
NAME               AGE
3
anyuid             38d
4
hostaccess         38d
5
hostmount-anyuid   38d
6
hostnetwork        38d
7
node-exporter      38d
8
nonroot            38d
9
privileged         38d
10
restricted         38d



4. To give more privileges to our service account so that images can get privileged access, we will use anyuid SCC

  • To add an SCC to a service account:
Shell
 




xxxxxxxxxx
1


 
1
$ oc adm policy add-scc-to-user <scc_name> \
2
    system:serviceaccount:<serviceaccount_namespace>:<serviceaccount_name>



Example from our openshift cluster:

Java
 




xxxxxxxxxx
1


 
1
 oc adm policy add-scc-to-user anyuid system:serviceaccount:test:robot 



  • If you are currently in the project to which the service account belongs, you can use the -z flag and just specify the <serviceaccount_name>.
Java
 




xxxxxxxxxx
1


 
1
$ oc adm policy add-scc-to-user <scc_name> -z <serviceaccount_name>



Example from our cluster:

Java
 




xxxxxxxxxx
1


 
1
oc adm policy add-scc-to-user anyuid -z robot


Usage of the -z flag as described above is highly recommended, as it helps prevent typos and ensures that access is granted only to the specified service account. If not in the project, use the -n option to indicate the project namespace it applies to.

5. We also need to create an Image pull secret as in our case image is present of Azure Container registry.

Shell
 




xxxxxxxxxx
1


1
$ oc create secret docker-registry <pull_secret_name> \
2
    --docker-server=<registry_server> \
3
    --docker-username=<user_name> \
4
    --docker-password=<password> \
5
    --docker-email=<email>


Note: we create image pull secret with name image-pull-test

6. Now we link pull secrets with default, builder & robot service accounts.

Java
 




xxxxxxxxxx
1


 
1
oc secrets link default image-pull-test  --for=pull oc secrets link robot image-pull-test  --for=pull


Note: we have created our service account which we will use as deployer as it will grant privileges to pods.

7. Once we have the pull secret in place and is linked to pull images, we can use the azure image stream to fetch the image tag for the local OCP cluster image registry:

Java
 




xxxxxxxxxx
1


 
1
# oc import-image sample-angular-app:latest --from=<registry-name>/sample-angular-app:latest --confirm



8. Once image stream is created, we need to create an application from it.

Java
 




xxxxxxxxxx
1


 
1
oc new-app <image-stream name> --name <application name>



9. Before we expose route we need to update deployment config so, we first need to find deployment config of our application

Shell
 




x


1
[root@hou0posa01 ~]# oc get dc
2
NAME                            REVISION   DESIRED   CURRENT   TRIGGERED BY
3
sample-angular-app               5          1         1         config,image(sample-angular-app:latest)
4
 
          



Since we were working with sample-angular-app  our dc(deployment-config) is sample-angular-app .

so we now need to edit it

Java
 




x


 
1
[root@hou0posa01 ~]# oc edit dc/sample-angular-app



It opens yml config in vi editor, we then added our custom service account in spec section:

YAML
 




x


1
 spec:
2
      containers:
3
      - image: <registry-name>/sample-angular-app@sha256:c03de1fc38e7878787889d5bb9eac0000008c478d14bb8fd59dd1cef9be809cea
4
        imagePullPolicy: Always
5
        name: sample-angular-app
6
        ports:
7
        - containerPort: 9090
8
          protocol: TCP
9
        resources: {}
10
        terminationMessagePath: /dev/termination-log
11
        terminationMessagePolicy: File
12
      dnsPolicy: ClusterFirst
13
      restartPolicy: Always
14
      schedulerName: default-scheduler
15
      securityContext: {}
16
      serviceAccount: robot
17
      serviceAccountName: robot
18
      terminationGracePeriodSeconds: 30



10. We then need to expose service i.e create a route. oc expose service <service name>

Reference link:

Running Pods With Particular UIDs – SCC Exploration With OpenShift

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.

Using specific user ids.

Conclusion

If the dev team already knows the directories on which privileged access is required and the number of directories on which privileges are required are not too much, then the first approach should be used. An example of the first approach would be our POC in which we deployed Angular UI application using NGINX.

The second approach is more useful if we require to install software on Openshift cluster and we don't know how many directories require privileges access. Also in case some directories are created dynamically during software execution, then the service account approach would be required. An example of the second approach would be to install a DB or any other software not present in OpenShift Catalog.

Topics:
cloud ,openshift 4.1 ,openshift application runtimes ,openshift container ,privileges ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}